diff options
author | Jan Luebbe <jlu@pengutronix.de> | 2012-11-22 11:58:36 +0100 |
---|---|---|
committer | Jan Luebbe <jlu@pengutronix.de> | 2012-11-22 12:46:51 +0100 |
commit | ce6e38fa64f60a7554546f39b7f462574719e484 (patch) | |
tree | 3e13722641d21ea0e6f4e752ed46b2dc7042c315 | |
parent | 25f57ac7c79468e9a2d3e4ae7473a75a7dd74d05 (diff) | |
download | platform-pengutronix-beaglebone-ce6e38fa64f60a7554546f39b7f462574719e484.tar.gz platform-pengutronix-beaglebone-ce6e38fa64f60a7554546f39b7f462574719e484.tar.xz |
kernel: switch to mainline-based patch stack
Thanks to Koen Kooi for maintaining the patch stack.
Also update to PTXdist master.
Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
132 files changed, 47464 insertions, 9 deletions
diff --git a/config/images/boot-mlo-vfat.config b/config/images/boot-mlo-vfat.config index 3b5f9b5..6a52246 100644 --- a/config/images/boot-mlo-vfat.config +++ b/config/images/boot-mlo-vfat.config @@ -3,6 +3,7 @@ image @IMAGE@ { file MLO { image = "MLO"} file barebox.bin { image = "barebox-image" } file barebox.env { image = "barebox-default-environment" } + file oftree { image = "am335x-bone.dtb" } file uImage { image = "linuximage" } } name = boot-mlo diff --git a/kernelconfig b/kernelconfig new file mode 100644 index 0000000..72894d1 --- /dev/null +++ b/kernelconfig @@ -0,0 +1,3890 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.7.0-rc6 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=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_VECTORS_BASE=0xffff0000 +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_NEED_MACH_GPIO_H=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y +CONFIG_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +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 is not set +# CONFIG_AUDIT 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_GENERIC_IRQ_CHIP=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set +CONFIG_SPARSE_IRQ=y +CONFIG_KTIME_SCALAR=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_PREEMPT_RCU 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_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_FREEZER is not set +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +# CONFIG_CGROUP_CPUACCT is not set +# CONFIG_RESOURCE_COUNTERS is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_SCHED_AUTOGROUP=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EXPERT=y +CONFIG_HAVE_UID16=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=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 is not set +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_COMPAT_BRK=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +CONFIG_OPROFILE=m +CONFIG_HAVE_OPROFILE=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +CONFIG_KRETPROBES=y +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_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_GENERIC_KERNEL_THREAD=y +CONFIG_GENERIC_KERNEL_EXECVE=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_REL=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=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +# 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=y + +# +# 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=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION 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_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_PADATA=y +CONFIG_ASN1=m +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=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_BCM2835 is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X 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_TEGRA is not set +# CONFIG_ARCH_PXA is not set +# 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_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_DAVINCI is not set +CONFIG_ARCH_OMAP=y +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set + +# +# TI OMAP Common Features +# +# CONFIG_ARCH_OMAP1 is not set +CONFIG_ARCH_OMAP2PLUS=y + +# +# OMAP Feature Selections +# +CONFIG_OMAP_RESET_CLOCKS=y +CONFIG_OMAP_MUX=y +CONFIG_OMAP_MUX_DEBUG=y +CONFIG_OMAP_MUX_WARNINGS=y +# CONFIG_OMAP_MBOX_FWK is not set +CONFIG_OMAP_32K_TIMER=y +# CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE is not set +CONFIG_OMAP_32K_TIMER_HZ=512 +CONFIG_OMAP_DM_TIMER=y +CONFIG_OMAP_PM_NOOP=y +CONFIG_MACH_OMAP_GENERIC=y + +# +# TI OMAP2/3/4 Specific Features +# +CONFIG_ARCH_OMAP2PLUS_TYPICAL=y +CONFIG_SOC_HAS_OMAP2_SDRC=y +# CONFIG_SOC_HAS_REALTIME_COUNTER is not set +# CONFIG_ARCH_OMAP2 is not set +CONFIG_ARCH_OMAP3=y +CONFIG_ARCH_OMAP4=y +# CONFIG_SOC_OMAP5 is not set +CONFIG_SOC_OMAP3430=y +# CONFIG_SOC_TI81XX is not set +CONFIG_SOC_AM33XX=y +CONFIG_OMAP_PACKAGE_CBB=y +CONFIG_OMAP_PACKAGE_CBL=y +CONFIG_OMAP_PACKAGE_CBS=y + +# +# OMAP Board Type +# +CONFIG_MACH_OMAP3_BEAGLE=y +# CONFIG_MACH_DEVKIT8000 is not set +# CONFIG_MACH_OMAP_LDP is not set +# CONFIG_MACH_OMAP3530_LV_SOM is not set +# CONFIG_MACH_OMAP3_TORPEDO is not set +# CONFIG_MACH_OVERO is not set +# CONFIG_MACH_OMAP3EVM is not set +# CONFIG_MACH_OMAP3517EVM is not set +# CONFIG_MACH_CRANEBOARD is not set +# CONFIG_MACH_OMAP3_PANDORA is not set +# CONFIG_MACH_TOUCHBOOK is not set +# CONFIG_MACH_OMAP_3430SDP is not set +# CONFIG_MACH_NOKIA_RM680 is not set +# CONFIG_MACH_NOKIA_RX51 is not set +# CONFIG_MACH_OMAP_ZOOM2 is not set +# CONFIG_MACH_OMAP_ZOOM3 is not set +# CONFIG_MACH_CM_T35 is not set +# CONFIG_MACH_CM_T3517 is not set +CONFIG_MACH_IGEP0020=y +# CONFIG_MACH_IGEP0030 is not set +# CONFIG_MACH_SBC3530 is not set +# CONFIG_MACH_OMAP_3630SDP is not set +# CONFIG_MACH_OMAP_4430SDP is not set +CONFIG_MACH_OMAP4_PANDA=y +# CONFIG_OMAP3_EMU is not set +# CONFIG_OMAP3_SDRC_AC_TIMING is not set +# CONFIG_OMAP4_ERRATA_I688 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=y +# CONFIG_ARM_VIRT_EXT is not set +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_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=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=y +CONFIG_ARM_ERRATA_720789=y +CONFIG_PL310_ERRATA_727915=y +# 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 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_PL310_ERRATA_769419 is not set +# CONFIG_ARM_ERRATA_775420 is not set +CONFIG_ARM_GIC=y +CONFIG_TI_PRIV_EDMA=y + +# +# 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_ARM_ARCH_TIMER is not set +CONFIG_HAVE_ARM_TWD=y +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_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_PREEMPT is not set +CONFIG_HZ=512 +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=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_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_COMPACTION is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +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=12 +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 + +# +# Boot options +# +CONFIG_USE_OF=y +CONFIG_ATAGS=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND 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_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +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_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_GENERIC_CPUFREQ_CPU0=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_OMAP2PLUS_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=y +# CONFIG_COREDUMP is not set + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=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=y +CONFIG_PM=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_ADVANCED_DEBUG is not set +# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_PM_SLEEP_DEBUG=y +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_OPP=y +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_DIAG=m +CONFIG_UNIX=y +CONFIG_UNIX_DIAG=m +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_MIGRATE=y +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IPGRE=m +# CONFIG_NET_IPGRE_BROADCAST is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_ARPD=y +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_LRO=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_UDP_DIAG=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=y +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_CUBIC=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MIP6=m +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_GRE=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_NETLABEL is not set +# CONFIG_NETWORK_SECMARK is not set +# 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_ACCT is not set +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NETFILTER_TPROXY is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +# CONFIG_NETFILTER_XT_MARK is not set + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +CONFIG_NETFILTER_XT_TARGET_HL=m +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ECN=m +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +CONFIG_NETFILTER_XT_MATCH_HL=m +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +CONFIG_IP_VS=m +# CONFIG_IP_VS_IPV6 is not set +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +# CONFIG_IP_VS_PROTO_TCP is not set +# CONFIG_IP_VS_PROTO_UDP is not set +# CONFIG_IP_VS_PROTO_AH_ESP is not set +# CONFIG_IP_VS_PROTO_ESP is not set +# CONFIG_IP_VS_PROTO_AH is not set +# CONFIG_IP_VS_PROTO_SCTP is not set + +# +# IPVS scheduler +# +# CONFIG_IP_VS_RR is not set +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS application helper +# + +# +# IP: Netfilter Configuration +# +# CONFIG_NF_DEFRAG_IPV4 is not set +CONFIG_IP_NF_QUEUE=m +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_ULOG=m +CONFIG_IP_NF_MANGLE=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 is not set +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_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +# CONFIG_BRIDGE_NF_EBTABLES is not set +# 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 is not set +CONFIG_STP=m +CONFIG_GARP=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_IGMP_SNOOPING=y +CONFIG_NET_DSA=m +# CONFIG_NET_DSA_TAG_DSA is not set +# CONFIG_NET_DSA_TAG_EDSA is not set +# CONFIG_NET_DSA_TAG_TRAILER is not set +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +# CONFIG_DECNET is not set +CONFIG_LLC=m +# 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_WAN_ROUTER is not set +CONFIG_PHONET=m +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +CONFIG_NET_SCH_CODEL=y +CONFIG_NET_SCH_FQ_CODEL=y +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +# CONFIG_NET_CLS_U32 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +CONFIG_NET_CLS_CGROUP=m +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +CONFIG_BATMAN_ADV=m +CONFIG_BATMAN_ADV_BLA=y +# CONFIG_BATMAN_ADV_DEBUG is not set +CONFIG_OPENVSWITCH=m +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +CONFIG_NETPRIO_CGROUP=m +CONFIG_BQL=y +CONFIG_BPF_JIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_DROP_MONITOR 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 is not set +# CONFIG_CAN_SLCAN is not set +CONFIG_CAN_DEV=m +CONFIG_CAN_CALC_BITTIMING=y +CONFIG_CAN_TI_HECC=m +CONFIG_CAN_MCP251X=m +# CONFIG_CAN_SJA1000 is not set +CONFIG_CAN_C_CAN=m +CONFIG_CAN_C_CAN_PLATFORM=m +# CONFIG_CAN_CC770 is not set + +# +# CAN USB interfaces +# +CONFIG_CAN_EMS_USB=m +CONFIG_CAN_ESD_USB2=m +CONFIG_CAN_PEAK_USB=m +# CONFIG_CAN_SOFTING is not set +# CONFIG_CAN_DEBUG_DEVICES is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +# CONFIG_IRNET is not set +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_TOIM3232_DONGLE=m +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m +CONFIG_KINGSUN_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_KS959_DONGLE=m + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +# CONFIG_SIGMATEL_FIR is not set +CONFIG_MCS_FIR=m +CONFIG_BT=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIBTUSB=m +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART=m +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 is not set +# CONFIG_BT_MRVL is not set +CONFIG_BT_ATH3K=m +# CONFIG_BT_WILINK is not set +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +# CONFIG_RXKAD 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_CFG80211=m +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +CONFIG_CFG80211_DEFAULT_PS=y +CONFIG_CFG80211_DEBUGFS=y +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +CONFIG_LIB80211=m +# CONFIG_LIB80211_DEBUG is not set +CONFIG_MAC80211=m +CONFIG_MAC80211_HAS_RC=y +CONFIG_MAC80211_RC_PID=y +CONFIG_MAC80211_RC_MINSTREL=y +CONFIG_MAC80211_RC_MINSTREL_HT=y +CONFIG_MAC80211_RC_DEFAULT_PID=y +# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set +CONFIG_MAC80211_RC_DEFAULT="pid" +CONFIG_MAC80211_MESH=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_DEBUGFS=y +# CONFIG_MAC80211_MESSAGE_TRACING is not set +# CONFIG_MAC80211_DEBUG_MENU is not set +CONFIG_WIMAX=m +CONFIG_WIMAX_DEBUG_LEVEL=8 +CONFIG_RFKILL=m +CONFIG_RFKILL_LEDS=y +CONFIG_RFKILL_INPUT=y +CONFIG_RFKILL_REGULATOR=m +CONFIG_RFKILL_GPIO=m +CONFIG_NET_9P=m +CONFIG_NET_9P_VIRTIO=m +# CONFIG_NET_9P_DEBUG is not set +# CONFIG_CAIF is not set +CONFIG_CEPH_LIB=m +# CONFIG_CEPH_LIB_PRETTYDEBUG is not set +# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set +CONFIG_NFC=m +CONFIG_NFC_NCI=m +CONFIG_NFC_HCI=m +CONFIG_NFC_SHDLC=y +# CONFIG_NFC_LLCP is not set + +# +# Near Field Communication (NFC) devices +# +CONFIG_PN544_HCI_NFC=m +CONFIG_NFC_PN533=m +# CONFIG_NFC_WILINK is not set +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# 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_DEBUG_DRIVER 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=m +CONFIG_REGMAP_MMIO=y +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_CMA is not set + +# +# Bus devices +# +CONFIG_OMAP_OCP2SCP=y +CONFIG_OMAP_INTERCONNECT=y +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# 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_CHAR=y +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=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS 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_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# 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_PHYSMAP is not set +# CONFIG_MTD_PHYSMAP_OF 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_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_DOCG3 is not set +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_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_OMAP2=y +# CONFIG_MTD_NAND_OMAP_BCH is not set +CONFIG_MTD_NAND_IDS=y +# 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=y +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +# CONFIG_MTD_ONENAND_GENERIC is not set +CONFIG_MTD_ONENAND_OMAP2=y +# CONFIG_MTD_ONENAND_OTP is not set +# CONFIG_MTD_ONENAND_2X_PROGRAM is not set +# CONFIG_MTD_ONENAND_SIM is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_FASTMAP=y +# CONFIG_MTD_UBI_GLUEBI is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +CONFIG_PROC_DEVICETREE=y +# CONFIG_OF_SELFTEST is not set +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 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 is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=16384 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +CONFIG_VIRTIO_BLK=m +# 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_ICS932S401 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=m +# 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_BMP085=y +CONFIG_BMP085_I2C=m +# CONFIG_BMP085_SPI is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_GPEVT is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_AT24=y +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=y +# CONFIG_EEPROM_93XX46 is not set + +# +# Texas Instruments shared transport line discipline +# +CONFIG_TI_ST=m +# 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 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=y + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# 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 is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +CONFIG_SCSI_VIRTIO=m +# 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 is not set +# CONFIG_BLK_DEV_DM is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +CONFIG_VXLAN=m +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=m +# CONFIG_VETH is not set +CONFIG_VIRTIO_NET=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_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +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_NET_VENDOR_MICREL=y +CONFIG_KS8842=m +CONFIG_KS8851=y +CONFIG_KS8851_MLL=y +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_SEEQ8005 is not set +CONFIG_NET_VENDOR_SMSC=y +CONFIG_SMC91X=y +# CONFIG_SMC911X is not set +CONFIG_SMSC911X=y +# CONFIG_SMSC911X_ARCH_HOOKS is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_NET_VENDOR_TI=y +CONFIG_TI_DAVINCI_EMAC=y +CONFIG_TI_DAVINCI_MDIO=y +CONFIG_TI_DAVINCI_CPDMA=y +CONFIG_TI_CPSW=y +CONFIG_NET_VENDOR_WIZNET=y +# CONFIG_WIZNET_W5100 is not set +# CONFIG_WIZNET_W5300 is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +CONFIG_AT803X_PHY=y +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_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=y +# 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=m +# CONFIG_MDIO_BUS_MUX_GPIO is not set +CONFIG_MDIO_BUS_MUX_MMIOREG=m +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SMSC75XX is not set +CONFIG_USB_NET_SMSC95XX=y +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_CDC_PHONET is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +CONFIG_WLAN=y +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_RTL8187 is not set +# CONFIG_MAC80211_HWSIM is not set +# CONFIG_ATH_COMMON is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_SDIO=m +# CONFIG_LIBERTAS_SPI is not set +CONFIG_LIBERTAS_DEBUG=y +# CONFIG_LIBERTAS_MESH is not set +# CONFIG_P54_COMMON is not set +# CONFIG_RT2X00 is not set +# CONFIG_RTL8192CU is not set +# CONFIG_WL_TI is not set +# CONFIG_ZD1211RW is not set +# CONFIG_MWIFIEX is not set + +# +# WiMAX Wireless Broadband devices +# +# CONFIG_WIMAX_I2400M_USB is not set +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +CONFIG_INPUT_MATRIXKMAP=y + +# +# 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=y +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG 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=y +# 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_OMAP4 is not set +CONFIG_KEYBOARD_TWL4030=y +# 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_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_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 is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=y +# 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=m +# 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=m +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +CONFIG_TOUCHSCREEN_TI_AM335X_TSC=y +# CONFIG_TOUCHSCREEN_PIXCIR is not set +CONFIG_TOUCHSCREEN_WM97XX=m +CONFIG_TOUCHSCREEN_WM9705=y +CONFIG_TOUCHSCREEN_WM9712=y +CONFIG_TOUCHSCREEN_WM9713=y +# 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_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 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_TWL4030_PWRBUTTON=y +# CONFIG_INPUT_TWL4030_VIBRA is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +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=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_EM 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_OF_PLATFORM is not set +CONFIG_SERIAL_OMAP=y +CONFIG_SERIAL_OMAP_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_TTY_PRINTK is not set +CONFIG_HVC_DRIVER=y +# CONFIG_HVC_DCC is not set +CONFIG_VIRTIO_CONSOLE=m +# 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_VIRTIO=m +# 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_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +CONFIG_I2C_OMAP=y +# 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_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_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +CONFIG_SPI_OMAP24XX=y +# CONFIG_SPI_PXA2XX_PCI is not set +CONFIG_SPI_SC18IS602=m +CONFIG_SPI_XCOMM=m +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_PINCTRL=y + +# +# Pin controllers +# +CONFIG_PINMUX=y +CONFIG_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +CONFIG_PINCTRL_SINGLE=y +# CONFIG_PINCTRL_SAMSUNG is not set +# CONFIG_PINCTRL_EXYNOS4 is not set +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_OF_GPIO=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_EM 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_TWL4030=y +# 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: +# +CONFIG_W1=y +CONFIG_W1_CON=y + +# +# 1-wire Bus Masters +# +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_DS1WM=m +CONFIG_W1_MASTER_GPIO=y +CONFIG_HDQ_MASTER_OMAP=m + +# +# 1-wire Slaves +# +CONFIG_W1_SLAVE_THERM=y +CONFIG_W1_SLAVE_SMEM=y +CONFIG_W1_SLAVE_DS2408=m +CONFIG_W1_SLAVE_DS2423=m +CONFIG_W1_SLAVE_DS2431=m +CONFIG_W1_SLAVE_DS2433=m +CONFIG_W1_SLAVE_DS2433_CRC=y +CONFIG_W1_SLAVE_DS2760=m +CONFIG_W1_SLAVE_DS2780=m +CONFIG_W1_SLAVE_DS2781=m +CONFIG_W1_SLAVE_DS28E04=m +CONFIG_W1_SLAVE_BQ27000=m +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +CONFIG_GENERIC_ADC_BATTERY=m +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2760 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_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_TWL4030 is not set +# CONFIG_CHARGER_LP8727 is not set +CONFIG_CHARGER_GPIO=m +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_SMB347 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_ADT7410=m +# 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=m +CONFIG_SENSORS_HIH6130=m +# 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_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=m +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MCP3021 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=m +# 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_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +CONFIG_SENSORS_TMP102=m +# 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_CPU_THERMAL=y +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_CORE is not set +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_MPCORE_WATCHDOG is not set +CONFIG_OMAP_WATCHDOG=y +CONFIG_TWL4030_WATCHDOG=y +# 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=y +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +CONFIG_MFD_TI_AM335X_TSCADC=y +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_UCB1400_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +CONFIG_MFD_TPS65217=y +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +CONFIG_TWL4030_CORE=y +# CONFIG_TWL4030_MADC is not set +CONFIG_TWL4030_POWER=y +# CONFIG_MFD_TWL4030_AUDIO is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB 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_PMIC_ADP5520 is not set +# CONFIG_MFD_LP8788 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_MFD_SEC_CORE 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_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +CONFIG_MFD_WL1273_CORE=m +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_PALMAS is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# 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_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_TPS62360 is not set +CONFIG_REGULATOR_TPS65023=y +CONFIG_REGULATOR_TPS6507X=y +CONFIG_REGULATOR_TPS65217=y +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_REGULATOR_TWL4030=y +CONFIG_MEDIA_SUPPORT=m + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_RC_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_V4L2=m +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEO_TUNER=m +CONFIG_V4L2_MEM2MEM_DEV=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEOBUF_DMA_CONTIG=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEOBUF2_CORE=m +CONFIG_VIDEOBUF2_MEMOPS=m +CONFIG_VIDEOBUF2_DMA_CONTIG=m +CONFIG_VIDEOBUF2_VMALLOC=m +CONFIG_DVB_CORE=m +CONFIG_DVB_NET=y +CONFIG_DVB_MAX_ADAPTERS=8 +CONFIG_DVB_DYNAMIC_MINORS=y + +# +# Media drivers +# +CONFIG_RC_CORE=m +CONFIG_RC_MAP=m +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_REDRAT3=m +CONFIG_IR_STREAMZAP=m +CONFIG_IR_IGUANA=m +CONFIG_IR_TTUSBIR=m +CONFIG_IR_RX51=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 is not set +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_AU0828=m +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_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_CYPRESS_FIRMWARE=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_SMS_USB_DRV is not set +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_TTPCI_EEPROM=m +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_VPSS_SYSTEM=m +CONFIG_VIDEO_VPFE_CAPTURE=m +CONFIG_VIDEO_DM6446_CCDC=m +CONFIG_VIDEO_OMAP2_VOUT_VRFB=y +CONFIG_VIDEO_OMAP2_VOUT=m +# CONFIG_VIDEO_TIMBERDALE is not set +CONFIG_SOC_CAMERA=m +CONFIG_SOC_CAMERA_PLATFORM=m +# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_MEM2MEM_DEINTERLACE=m +CONFIG_V4L_TEST_DRIVERS=y +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_MEM2MEM_TESTDEV=m + +# +# Supported MMC/SDIO adapters +# +# CONFIG_SMS_SDIO_DRV is not set +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_SI470X=y +CONFIG_USB_SI470X=m +CONFIG_I2C_SI470X=m +CONFIG_USB_MR800=m +CONFIG_USB_DSBR=m +# CONFIG_RADIO_SHARK is not set +CONFIG_RADIO_SHARK2=m +CONFIG_I2C_SI4713=m +CONFIG_RADIO_SI4713=m +CONFIG_USB_KEENE=m +CONFIG_RADIO_TEA5764=m +CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_TEF6862=m +CONFIG_RADIO_WL1273=m + +# +# Texas Instruments WL128x FM driver (ST based) +# +CONFIG_RADIO_WL128X=m +CONFIG_DVB_B2C2_FLEXCOP=m +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# +CONFIG_VIDEO_TVEEPROM=m +CONFIG_VIDEO_IR_I2C=m + +# +# 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 + +# +# MPEG video encoders +# +CONFIG_VIDEO_CX2341X=m + +# +# Video encoders +# + +# +# Camera sensor devices +# +CONFIG_VIDEO_MT9V011=m + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# + +# +# Sensors used on soc_camera driver +# + +# +# soc_camera sensor drivers +# +# CONFIG_SOC_CAMERA_IMX074 is not set +CONFIG_SOC_CAMERA_MT9M001=m +CONFIG_SOC_CAMERA_MT9M111=m +CONFIG_SOC_CAMERA_MT9T031=m +CONFIG_SOC_CAMERA_MT9T112=m +CONFIG_SOC_CAMERA_MT9V022=m +# CONFIG_SOC_CAMERA_OV2640 is not set +# CONFIG_SOC_CAMERA_OV5642 is not set +# CONFIG_SOC_CAMERA_OV6650 is not set +# CONFIG_SOC_CAMERA_OV772X is not set +# CONFIG_SOC_CAMERA_OV9640 is not set +# CONFIG_SOC_CAMERA_OV9740 is not set +# CONFIG_SOC_CAMERA_RJ54N1 is not set +# CONFIG_SOC_CAMERA_TW9910 is not set +CONFIG_MEDIA_ATTACH=y +CONFIG_MEDIA_TUNER=m +CONFIG_MEDIA_TUNER_SIMPLE=m +CONFIG_MEDIA_TUNER_TDA8290=m +CONFIG_MEDIA_TUNER_TDA827X=m +CONFIG_MEDIA_TUNER_TDA18271=m +CONFIG_MEDIA_TUNER_TDA9887=m +CONFIG_MEDIA_TUNER_TEA5761=m +CONFIG_MEDIA_TUNER_TEA5767=m +CONFIG_MEDIA_TUNER_MT20XX=m +CONFIG_MEDIA_TUNER_MT2060=m +CONFIG_MEDIA_TUNER_MT2063=m +CONFIG_MEDIA_TUNER_MT2266=m +CONFIG_MEDIA_TUNER_QT1010=m +CONFIG_MEDIA_TUNER_XC2028=m +CONFIG_MEDIA_TUNER_XC5000=m +CONFIG_MEDIA_TUNER_XC4000=m +CONFIG_MEDIA_TUNER_MXL5005S=m +CONFIG_MEDIA_TUNER_MXL5007T=m +CONFIG_MEDIA_TUNER_MC44S803=m +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_TUA9001=m + +# +# Multistandard (satellite) frontends +# +CONFIG_DVB_STB0899=m +CONFIG_DVB_STB6100=m +CONFIG_DVB_STV090x=m +CONFIG_DVB_STV6110x=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_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 + +# +# 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_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 is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +# 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=y +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +CONFIG_FB_FOREIGN_ENDIAN=y +CONFIG_FB_BOTH_ENDIAN=y +# CONFIG_FB_BIG_ENDIAN is not set +# CONFIG_FB_LITTLE_ENDIAN is not set +CONFIG_FB_SYS_FOPS=y +# CONFIG_FB_WMT_GE_ROPS is not set +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_UVESA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +CONFIG_FB_DA8XX=y +# 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_ST7735=y +CONFIG_OMAP2_VRAM=y +CONFIG_OMAP2_VRFB=y +CONFIG_OMAP2_DSS=m +CONFIG_OMAP2_VRAM_SIZE=0 +CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y +# CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS is not set +CONFIG_OMAP2_DSS_DPI=y +CONFIG_OMAP2_DSS_RFBI=y +CONFIG_OMAP2_DSS_VENC=y +CONFIG_OMAP4_DSS_HDMI=y +CONFIG_OMAP2_DSS_SDI=y +CONFIG_OMAP2_DSS_DSI=y +CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0 +CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET=y +CONFIG_FB_OMAP2=m +CONFIG_FB_OMAP2_DEBUG_SUPPORT=y +CONFIG_FB_OMAP2_NUM_FBS=3 + +# +# OMAP2/3 Display Device Drivers +# +CONFIG_PANEL_GENERIC_DPI=m +# CONFIG_PANEL_TFP410 is not set +# CONFIG_PANEL_LGPHILIPS_LB035Q02 is not set +CONFIG_PANEL_SHARP_LS037V7DW01=m +CONFIG_PANEL_NEC_NL8048HL11_01B=m +# CONFIG_PANEL_PICODLP is not set +CONFIG_PANEL_TAAL=m +CONFIG_PANEL_TPO_TD043MTEA1=m +CONFIG_PANEL_ACX565AKM=m +# CONFIG_PANEL_N8X0 is not set +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +CONFIG_LCD_ILI9320=y +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +CONFIG_LCD_PLATFORM=y +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_AMS369FG06 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=m +CONFIG_BACKLIGHT_PWM=y +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +CONFIG_BACKLIGHT_LM3630=m +CONFIG_BACKLIGHT_LM3639=m +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_PANDORA is not set +CONFIG_BACKLIGHT_TPS65217=y + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +CONFIG_FONT_MINI_4x6=y +# 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_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_COMPRESS_OFFLOAD=m +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER 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_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +CONFIG_SND_VERBOSE_PRINTK=y +CONFIG_SND_DEBUG=y +# CONFIG_SND_DEBUG_VERBOSE is not set +# CONFIG_SND_PCM_XRUN_DEBUG is not set +CONFIG_SND_VMASTER=y +# CONFIG_SND_RAWMIDI_SEQ is not set +# 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 is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 +CONFIG_SND_ARM=y +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=m +# CONFIG_SND_DESIGNWARE_I2S is not set +CONFIG_SND_SOC_I2C_AND_SPI=m +# CONFIG_SND_SOC_ALL_CODECS is not set +# 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 is not set +CONFIG_UHID=m +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LCPOWER is not set +CONFIG_HID_LENOVO_TPKBD=m +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PRIMAX is not set +CONFIG_HID_PS3REMOTE=m +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +CONFIG_HID_SENSOR_HUB=m + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# 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=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_DWC3 is not set +CONFIG_USB_MON=y +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_EHCI_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_OHCI_HCD is not set +# CONFIG_USB_U132_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +CONFIG_USB_MUSB_HDRC=y +# CONFIG_USB_MUSB_TUSB6010 is not set +# CONFIG_USB_MUSB_OMAP2PLUS is not set +# CONFIG_USB_MUSB_AM35X is not set +CONFIG_USB_MUSB_DSPS=y +CONFIG_MUSB_PIO_ONLY=y +# CONFIG_USB_CHIPIDEA 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=m + +# +# 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 +CONFIG_USB_UAS=y + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +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_FUNSOFT=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_MOS7840=m +CONFIG_USB_SERIAL_MOTOROLA=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_HP4X=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIEMENS_MPI=m +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_VIVOPAY_SERIAL=m +CONFIG_USB_SERIAL_ZIO=m +CONFIG_USB_SERIAL_ZTE=m +CONFIG_USB_SERIAL_SSU100=m +CONFIG_USB_SERIAL_QT2=m +CONFIG_USB_SERIAL_DEBUG=m + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_SEVSEG=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_LED=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_SISUSBVGA=m +CONFIG_USB_SISUSBVGA_CON=y +CONFIG_USB_LD=m +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_TEST=m +CONFIG_USB_ISIGHTFW=m +CONFIG_USB_YUREX=m +CONFIG_USB_EZUSB_FX2=m + +# +# USB Physical Layer drivers +# +CONFIG_OMAP_USB2=y +CONFIG_USB_ISP1301=m +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_MV_UDC is not set +CONFIG_USB_GADGET_MUSB_HDRC=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_ZERO is not set +# CONFIG_USB_AUDIO is not set +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +# CONFIG_USB_ETH_EEM is not set +# CONFIG_USB_G_NCM is not set +CONFIG_USB_GADGETFS=m +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_G_SERIAL=m +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_CDC_COMPOSITE=m +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +CONFIG_USB_G_HID=m +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +CONFIG_USB_GPIO_VBUS=m +# CONFIG_USB_ULPI is not set +CONFIG_TWL6030_USB=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_UNSAFE_RESUME=y +# CONFIG_MMC_CLKGATE is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_SDIO_UART=y +# 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_OMAP=y +CONFIG_MMC_OMAP_HS=y +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +CONFIG_LEDS_LM3642=m +# 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_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_DAC124S085 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=m +# CONFIG_LEDS_OT200 is not set +CONFIG_LEDS_BLINKM=m +CONFIG_LEDS_TRIGGERS=y + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y + +# +# iptables trigger is under Netfilter config (LED target) +# +CONFIG_LEDS_TRIGGER_TRANSIENT=y +# CONFIG_ACCESSIBILITY is not set +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=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_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_TWL4030=y +# 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 + +# +# 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=m + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_SNVS=m +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +# CONFIG_DW_DMAC is not set +# CONFIG_TIMB_DMA is not set +CONFIG_TI_EDMA=y +# CONFIG_DMA_OMAP is not set +CONFIG_DMA_ENGINE=y +CONFIG_DMA_VIRTUAL_CHANNELS=y + +# +# DMA Clients +# +CONFIG_NET_DMA=y +CONFIG_ASYNC_TX_DMA=y +CONFIG_DMATEST=m +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +CONFIG_UIO_PDRV=y +CONFIG_UIO_PDRV_GENIRQ=y +CONFIG_VIRTIO=m + +# +# Virtio drivers +# +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_STAGING is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HWSPINLOCK=m + +# +# Hardware Spinlock drivers +# +CONFIG_HWSPINLOCK_OMAP=m +CONFIG_CLKSRC_MMIO=y +CONFIG_IOMMU_SUPPORT=y +CONFIG_OF_IOMMU=y +# CONFIG_OMAP_IOMMU is not set + +# +# Remoteproc drivers (EXPERIMENTAL) +# +CONFIG_REMOTEPROC=m +CONFIG_STE_MODEM_RPROC=m + +# +# Rpmsg drivers (EXPERIMENTAL) +# +# CONFIG_VIRT_DRIVERS is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +CONFIG_IIO=y +CONFIG_IIO_BUFFER=y +CONFIG_IIO_KFIFO_BUF=m +CONFIG_IIO_TRIGGERED_BUFFER=m +CONFIG_IIO_TRIGGER=y +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 + +# +# Accelerometers +# +CONFIG_HID_SENSOR_ACCEL_3D=m + +# +# Analog to digital converters +# +CONFIG_AD_SIGMA_DELTA=m +CONFIG_AD7266=m +CONFIG_AD7791=m +CONFIG_AD7476=m +CONFIG_TI_AM335X_ADC=y + +# +# Amplifiers +# +# CONFIG_AD8366 is not set + +# +# Light sensors +# +CONFIG_ADJD_S311=m +CONFIG_VCNL4000=m +CONFIG_HID_SENSOR_ALS=m + +# +# Frequency Synthesizers DDS/PLL +# + +# +# Clock Generator/Distribution +# +CONFIG_AD9523=m + +# +# Phase-Locked Loop (PLL) frequency synthesizers +# +CONFIG_ADF4350=m + +# +# Digital to analog converters +# +CONFIG_AD5064=m +CONFIG_AD5360=m +CONFIG_AD5380=m +CONFIG_AD5421=m +CONFIG_AD5624R_SPI=m +CONFIG_AD5446=m +CONFIG_AD5504=m +CONFIG_AD5755=m +CONFIG_AD5764=m +CONFIG_AD5791=m +CONFIG_AD5686=m +CONFIG_MAX517=m +CONFIG_MCP4725=m + +# +# Hid Sensor IIO Common +# +CONFIG_HID_SENSOR_IIO_COMMON=m +CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS=m + +# +# Digital gyroscope sensors +# +CONFIG_HID_SENSOR_GYRO_3D=m + +# +# Magnetometer sensors +# +CONFIG_HID_SENSOR_MAGNETOMETER_3D=m +CONFIG_PWM=y +CONFIG_PWM_TIECAP=y +CONFIG_PWM_TIEHRPWM=y +# CONFIG_PWM_TWL6030 is not set +CONFIG_EHRPWM_TEST=m + +# +# CAPEBUS support +# +CONFIG_CAPEBUS=y +CONFIG_CAPEBUS_BONE_CONTROLLER=y +CONFIG_CAPEBUS_BONE_GENERIC=y +CONFIG_CAPEBUS_BONE_GEIGER=y + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_DEFAULTS_TO_ORDERED=y +# CONFIG_EXT3_FS_XATTR is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +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 is not set +# CONFIG_REISERFS_FS_XATTR is not set +CONFIG_JFS_FS=m +# CONFIG_JFS_POSIX_ACL is not set +# CONFIG_JFS_SECURITY is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_XFS_FS=m +CONFIG_XFS_QUOTA=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +# CONFIG_XFS_DEBUG is not set +CONFIG_GFS2_FS=m +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +CONFIG_NILFS2_FS=m +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=m +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=m + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# 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 is not set + +# +# 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 is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_FS_POSIX_ACL=y +CONFIG_JFFS2_FS_SECURITY=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +CONFIG_JFFS2_RUBIN=y +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +# CONFIG_LOGFS is not set +CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# 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=y +CONFIG_F2FS_STAT_FS=y +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_FS_POSIX_ACL=y +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_SWAP=y +# CONFIG_NFS_V4_1 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_SUNRPC_SWAP=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 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 is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_SCHED_DEBUG=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# 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_SPARSE_RCU_POINTER 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=y +CONFIG_DEBUG_INFO_REDUCED=y +# 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 +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_KPROBES_SANITY_TEST 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=m +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +CONFIG_PM_NOTIFIER_ERROR_INJECT=m +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +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_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_EVENT_POWER_TRACING_DEPRECATED=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_RING_BUFFER_ALLOW_SWAP=y +CONFIG_TRACING=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +# CONFIG_FTRACE_SYSCALLS 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_KPROBE_EVENT=y +CONFIG_PROBE_EVENTS=y +# CONFIG_RING_BUFFER_BENCHMARK 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_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB 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_LL is not set +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +# CONFIG_ARM_KPROBES_TEST is not set +# 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 is not set +# CONFIG_SECURITY_PATH is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_IMA is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +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=m +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +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 is not set +# CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_PCRYPT=y +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=m +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_MICHAEL_MIC=y +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=m +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_AES_ARM=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_OMAP_SHAM is not set +# CONFIG_CRYPTO_DEV_OMAP_AES is not set +CONFIG_ASYMMETRIC_KEY_TYPE=m +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m +CONFIG_PUBLIC_KEY_ALGO_RSA=m +CONFIG_X509_CERTIFICATE_PARSER=m +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +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_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +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_AVERAGE=y +CONFIG_CLZ_TAB=y +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_MPILIB=m +CONFIG_OID_REGISTRY=m diff --git a/patches/linux-3.7-rc6/0000-linux-master.patch b/patches/linux-3.7-rc6/0000-linux-master.patch new file mode 100644 index 0000000..d0fc85b --- /dev/null +++ b/patches/linux-3.7-rc6/0000-linux-master.patch @@ -0,0 +1,503 @@ +diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c +index 1e6956a..14db93e 100644 +--- a/arch/alpha/kernel/osf_sys.c ++++ b/arch/alpha/kernel/osf_sys.c +@@ -445,7 +445,7 @@ struct procfs_args { + * unhappy with OSF UFS. [CHECKME] + */ + static int +-osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags) ++osf_ufs_mount(const char *dirname, struct ufs_args __user *args, int flags) + { + int retval; + struct cdfs_args tmp; +@@ -465,7 +465,7 @@ osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags) + } + + static int +-osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags) ++osf_cdfs_mount(const char *dirname, struct cdfs_args __user *args, int flags) + { + int retval; + struct cdfs_args tmp; +@@ -485,7 +485,7 @@ osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags) + } + + static int +-osf_procfs_mount(char *dirname, struct procfs_args __user *args, int flags) ++osf_procfs_mount(const char *dirname, struct procfs_args __user *args, int flags) + { + struct procfs_args tmp; + +diff --git a/arch/m68k/include/asm/signal.h b/arch/m68k/include/asm/signal.h +index 67e489d..2df26b5 100644 +--- a/arch/m68k/include/asm/signal.h ++++ b/arch/m68k/include/asm/signal.h +@@ -41,7 +41,7 @@ struct k_sigaction { + static inline void sigaddset(sigset_t *set, int _sig) + { + asm ("bfset %0{%1,#1}" +- : "+od" (*set) ++ : "+o" (*set) + : "id" ((_sig - 1) ^ 31) + : "cc"); + } +@@ -49,7 +49,7 @@ static inline void sigaddset(sigset_t *set, int _sig) + static inline void sigdelset(sigset_t *set, int _sig) + { + asm ("bfclr %0{%1,#1}" +- : "+od" (*set) ++ : "+o" (*set) + : "id" ((_sig - 1) ^ 31) + : "cc"); + } +@@ -65,7 +65,7 @@ static inline int __gen_sigismember(sigset_t *set, int _sig) + int ret; + asm ("bfextu %1{%2,#1},%0" + : "=d" (ret) +- : "od" (*set), "id" ((_sig-1) ^ 31) ++ : "o" (*set), "id" ((_sig-1) ^ 31) + : "cc"); + return ret; + } +diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c +index b1ae480..b7078af 100644 +--- a/drivers/ata/ahci_platform.c ++++ b/drivers/ata/ahci_platform.c +@@ -238,7 +238,7 @@ static int __devexit ahci_remove(struct platform_device *pdev) + return 0; + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int ahci_suspend(struct device *dev) + { + struct ahci_platform_data *pdata = dev_get_platdata(dev); +diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c +index fd9ecf7..5b0ba3f 100644 +--- a/drivers/ata/libata-acpi.c ++++ b/drivers/ata/libata-acpi.c +@@ -1105,10 +1105,15 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev, + struct acpi_device *acpi_dev; + struct acpi_device_power_state *states; + +- if (ap->flags & ATA_FLAG_ACPI_SATA) +- ata_dev = &ap->link.device[sdev->channel]; +- else ++ if (ap->flags & ATA_FLAG_ACPI_SATA) { ++ if (!sata_pmp_attached(ap)) ++ ata_dev = &ap->link.device[sdev->id]; ++ else ++ ata_dev = &ap->pmp_link[sdev->channel].device[sdev->id]; ++ } ++ else { + ata_dev = &ap->link.device[sdev->id]; ++ } + + *handle = ata_dev_acpi_handle(ata_dev); + +diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c +index 3cc7096..f46fbd3 100644 +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -2942,6 +2942,10 @@ const struct ata_timing *ata_timing_find_mode(u8 xfer_mode) + + if (xfer_mode == t->mode) + return t; ++ ++ WARN_ONCE(true, "%s: unable to find timing for xfer_mode 0x%x\n", ++ __func__, xfer_mode); ++ + return NULL; + } + +diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c +index 26201eb..371fd2c 100644 +--- a/drivers/ata/pata_arasan_cf.c ++++ b/drivers/ata/pata_arasan_cf.c +@@ -317,6 +317,12 @@ static int cf_init(struct arasan_cf_dev *acdev) + return ret; + } + ++ ret = clk_set_rate(acdev->clk, 166000000); ++ if (ret) { ++ dev_warn(acdev->host->dev, "clock set rate failed"); ++ return ret; ++ } ++ + spin_lock_irqsave(&acdev->host->lock, flags); + /* configure CF interface clock */ + writel((pdata->cf_if_clk <= CF_IF_CLK_200M) ? pdata->cf_if_clk : +@@ -908,7 +914,7 @@ static int __devexit arasan_cf_remove(struct platform_device *pdev) + return 0; + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int arasan_cf_suspend(struct device *dev) + { + struct ata_host *host = dev_get_drvdata(dev); +diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c +index 0d7c4c2..400bf1c 100644 +--- a/drivers/ata/sata_highbank.c ++++ b/drivers/ata/sata_highbank.c +@@ -260,7 +260,7 @@ static const struct of_device_id ahci_of_match[] = { + }; + MODULE_DEVICE_TABLE(of, ahci_of_match); + +-static int __init ahci_highbank_probe(struct platform_device *pdev) ++static int __devinit ahci_highbank_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; + struct ahci_host_priv *hpriv; +@@ -378,7 +378,7 @@ static int __devexit ahci_highbank_remove(struct platform_device *pdev) + return 0; + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int ahci_highbank_suspend(struct device *dev) + { + struct ata_host *host = dev_get_drvdata(dev); +diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c +index 44a4256..08608de 100644 +--- a/drivers/ata/sata_svw.c ++++ b/drivers/ata/sata_svw.c +@@ -142,6 +142,39 @@ static int k2_sata_scr_write(struct ata_link *link, + return 0; + } + ++static int k2_sata_softreset(struct ata_link *link, ++ unsigned int *class, unsigned long deadline) ++{ ++ u8 dmactl; ++ void __iomem *mmio = link->ap->ioaddr.bmdma_addr; ++ ++ dmactl = readb(mmio + ATA_DMA_CMD); ++ ++ /* Clear the start bit */ ++ if (dmactl & ATA_DMA_START) { ++ dmactl &= ~ATA_DMA_START; ++ writeb(dmactl, mmio + ATA_DMA_CMD); ++ } ++ ++ return ata_sff_softreset(link, class, deadline); ++} ++ ++static int k2_sata_hardreset(struct ata_link *link, ++ unsigned int *class, unsigned long deadline) ++{ ++ u8 dmactl; ++ void __iomem *mmio = link->ap->ioaddr.bmdma_addr; ++ ++ dmactl = readb(mmio + ATA_DMA_CMD); ++ ++ /* Clear the start bit */ ++ if (dmactl & ATA_DMA_START) { ++ dmactl &= ~ATA_DMA_START; ++ writeb(dmactl, mmio + ATA_DMA_CMD); ++ } ++ ++ return sata_sff_hardreset(link, class, deadline); ++} + + static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) + { +@@ -346,6 +379,8 @@ static struct scsi_host_template k2_sata_sht = { + + static struct ata_port_operations k2_sata_ops = { + .inherits = &ata_bmdma_port_ops, ++ .softreset = k2_sata_softreset, ++ .hardreset = k2_sata_hardreset, + .sff_tf_load = k2_sata_tf_load, + .sff_tf_read = k2_sata_tf_read, + .sff_check_status = k2_stat_check_status, +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index f11d8e3..47150f5 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -466,7 +466,7 @@ config GPIO_ADP5588_IRQ + + config GPIO_ADNP + tristate "Avionic Design N-bit GPIO expander" +- depends on I2C && OF ++ depends on I2C && OF_GPIO + help + This option enables support for N GPIOs found on Avionic Design + I2C GPIO expanders. The register space will be extended by powers +diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c +index 0f42518..ce1c847 100644 +--- a/drivers/gpio/gpio-mcp23s08.c ++++ b/drivers/gpio/gpio-mcp23s08.c +@@ -77,7 +77,7 @@ struct mcp23s08_driver_data { + + /*----------------------------------------------------------------------*/ + +-#ifdef CONFIG_I2C ++#if IS_ENABLED(CONFIG_I2C) + + static int mcp23008_read(struct mcp23s08 *mcp, unsigned reg) + { +@@ -399,7 +399,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, + break; + #endif /* CONFIG_SPI_MASTER */ + +-#ifdef CONFIG_I2C ++#if IS_ENABLED(CONFIG_I2C) + case MCP_TYPE_008: + mcp->ops = &mcp23008_ops; + mcp->chip.ngpio = 8; +@@ -473,7 +473,7 @@ fail: + + /*----------------------------------------------------------------------*/ + +-#ifdef CONFIG_I2C ++#if IS_ENABLED(CONFIG_I2C) + + static int __devinit mcp230xx_probe(struct i2c_client *client, + const struct i2c_device_id *id) +diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c +index cf7afb9..be65c04 100644 +--- a/drivers/gpio/gpio-mvebu.c ++++ b/drivers/gpio/gpio-mvebu.c +@@ -92,6 +92,11 @@ static inline void __iomem *mvebu_gpioreg_out(struct mvebu_gpio_chip *mvchip) + return mvchip->membase + GPIO_OUT_OFF; + } + ++static inline void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip) ++{ ++ return mvchip->membase + GPIO_BLINK_EN_OFF; ++} ++ + static inline void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) + { + return mvchip->membase + GPIO_IO_CONF_OFF; +@@ -206,6 +211,23 @@ static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin) + return (u >> pin) & 1; + } + ++static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value) ++{ ++ struct mvebu_gpio_chip *mvchip = ++ container_of(chip, struct mvebu_gpio_chip, chip); ++ unsigned long flags; ++ u32 u; ++ ++ spin_lock_irqsave(&mvchip->lock, flags); ++ u = readl_relaxed(mvebu_gpioreg_blink(mvchip)); ++ if (value) ++ u |= 1 << pin; ++ else ++ u &= ~(1 << pin); ++ writel_relaxed(u, mvebu_gpioreg_blink(mvchip)); ++ spin_unlock_irqrestore(&mvchip->lock, flags); ++} ++ + static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned pin) + { + struct mvebu_gpio_chip *mvchip = +@@ -244,6 +266,7 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin, + if (ret) + return ret; + ++ mvebu_gpio_blink(chip, pin, 0); + mvebu_gpio_set(chip, pin, value); + + spin_lock_irqsave(&mvchip->lock, flags); +diff --git a/fs/file.c b/fs/file.c +index 708d997..7cb71b9 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -685,7 +685,6 @@ void do_close_on_exec(struct files_struct *files) + struct fdtable *fdt; + + /* exec unshares first */ +- BUG_ON(atomic_read(&files->count) != 1); + spin_lock(&files->file_lock); + for (i = 0; ; i++) { + unsigned long set; +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 721d692..6fcaeb8 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -258,7 +258,8 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + if (ret) + goto out_close_fd; + +- fd_install(fd, f); ++ if (fd != FAN_NOFD) ++ fd_install(fd, f); + return fanotify_event_metadata.event_len; + + out_close_fd: +diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c +index e562dd4..e57e2da 100644 +--- a/fs/xfs/xfs_aops.c ++++ b/fs/xfs/xfs_aops.c +@@ -481,11 +481,17 @@ static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh) + * + * The fix is two passes across the ioend list - one to start writeback on the + * buffer_heads, and then submit them for I/O on the second pass. ++ * ++ * If @fail is non-zero, it means that we have a situation where some part of ++ * the submission process has failed after we have marked paged for writeback ++ * and unlocked them. In this situation, we need to fail the ioend chain rather ++ * than submit it to IO. This typically only happens on a filesystem shutdown. + */ + STATIC void + xfs_submit_ioend( + struct writeback_control *wbc, +- xfs_ioend_t *ioend) ++ xfs_ioend_t *ioend, ++ int fail) + { + xfs_ioend_t *head = ioend; + xfs_ioend_t *next; +@@ -506,6 +512,18 @@ xfs_submit_ioend( + next = ioend->io_list; + bio = NULL; + ++ /* ++ * If we are failing the IO now, just mark the ioend with an ++ * error and finish it. This will run IO completion immediately ++ * as there is only one reference to the ioend at this point in ++ * time. ++ */ ++ if (fail) { ++ ioend->io_error = -fail; ++ xfs_finish_ioend(ioend); ++ continue; ++ } ++ + for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) { + + if (!bio) { +@@ -1060,7 +1078,18 @@ xfs_vm_writepage( + + xfs_start_page_writeback(page, 1, count); + +- if (ioend && imap_valid) { ++ /* if there is no IO to be submitted for this page, we are done */ ++ if (!ioend) ++ return 0; ++ ++ ASSERT(iohead); ++ ++ /* ++ * Any errors from this point onwards need tobe reported through the IO ++ * completion path as we have marked the initial page as under writeback ++ * and unlocked it. ++ */ ++ if (imap_valid) { + xfs_off_t end_index; + + end_index = imap.br_startoff + imap.br_blockcount; +@@ -1079,20 +1108,15 @@ xfs_vm_writepage( + wbc, end_index); + } + +- if (iohead) { +- /* +- * Reserve log space if we might write beyond the on-disk +- * inode size. +- */ +- if (ioend->io_type != XFS_IO_UNWRITTEN && +- xfs_ioend_is_append(ioend)) { +- err = xfs_setfilesize_trans_alloc(ioend); +- if (err) +- goto error; +- } + +- xfs_submit_ioend(wbc, iohead); +- } ++ /* ++ * Reserve log space if we might write beyond the on-disk inode size. ++ */ ++ err = 0; ++ if (ioend->io_type != XFS_IO_UNWRITTEN && xfs_ioend_is_append(ioend)) ++ err = xfs_setfilesize_trans_alloc(ioend); ++ ++ xfs_submit_ioend(wbc, iohead, err); + + return 0; + +diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c +index d330111..70eec18 100644 +--- a/fs/xfs/xfs_attr_leaf.c ++++ b/fs/xfs/xfs_attr_leaf.c +@@ -1291,6 +1291,7 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + leaf2 = blk2->bp->b_addr; + ASSERT(leaf1->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC)); + ASSERT(leaf2->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC)); ++ ASSERT(leaf2->hdr.count == 0); + args = state->args; + + trace_xfs_attr_leaf_rebalance(args); +@@ -1361,6 +1362,7 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + * I assert that since all callers pass in an empty + * second buffer, this code should never execute. + */ ++ ASSERT(0); + + /* + * Figure the total bytes to be added to the destination leaf. +@@ -1422,10 +1424,24 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + args->index2 = 0; + args->blkno2 = blk2->blkno; + } else { ++ /* ++ * On a double leaf split, the original attr location ++ * is already stored in blkno2/index2, so don't ++ * overwrite it overwise we corrupt the tree. ++ */ + blk2->index = blk1->index + - be16_to_cpu(leaf1->hdr.count); +- args->index = args->index2 = blk2->index; +- args->blkno = args->blkno2 = blk2->blkno; ++ args->index = blk2->index; ++ args->blkno = blk2->blkno; ++ if (!state->extravalid) { ++ /* ++ * set the new attr location to match the old ++ * one and let the higher level split code ++ * decide where in the leaf to place it. ++ */ ++ args->index2 = blk2->index; ++ args->blkno2 = blk2->blkno; ++ } + } + } else { + ASSERT(state->inleaf == 1); +diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c +index 933b793..4b0b8dd 100644 +--- a/fs/xfs/xfs_buf.c ++++ b/fs/xfs/xfs_buf.c +@@ -1197,9 +1197,14 @@ xfs_buf_bio_end_io( + { + xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private; + +- xfs_buf_ioerror(bp, -error); ++ /* ++ * don't overwrite existing errors - otherwise we can lose errors on ++ * buffers that require multiple bios to complete. ++ */ ++ if (!bp->b_error) ++ xfs_buf_ioerror(bp, -error); + +- if (!error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) ++ if (!bp->b_error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) + invalidate_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp)); + + _xfs_buf_ioend(bp, 1); +@@ -1279,6 +1284,11 @@ next_chunk: + if (size) + goto next_chunk; + } else { ++ /* ++ * This is guaranteed not to be the last io reference count ++ * because the caller (xfs_buf_iorequest) holds a count itself. ++ */ ++ atomic_dec(&bp->b_io_remaining); + xfs_buf_ioerror(bp, EIO); + bio_put(bio); + } diff --git a/patches/linux-3.7-rc6/0001-video-st7735fb-add-st7735-framebuffer-driver.patch b/patches/linux-3.7-rc6/0001-video-st7735fb-add-st7735-framebuffer-driver.patch new file mode 100644 index 0000000..70cfb9c --- /dev/null +++ b/patches/linux-3.7-rc6/0001-video-st7735fb-add-st7735-framebuffer-driver.patch @@ -0,0 +1,800 @@ +From f24d7d872ab89aa8aec4ea0bf36c1c612906907b Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Tue, 11 Sep 2012 15:30:10 -0400 +Subject: [PATCH] video: st7735fb: add st7735 framebuffer driver + +Add driver for the SPI-connected ST7735 display controller. +This driver requires that the platform support DT booting. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + .../devicetree/bindings/vendor-prefixes.txt | 2 + + drivers/video/Kconfig | 11 + + drivers/video/Makefile | 1 + + drivers/video/st7735fb.c | 631 ++++++++++++++++++++ + drivers/video/st7735fb.h | 84 +++ + 5 files changed, 729 insertions(+) + create mode 100644 drivers/video/st7735fb.c + create mode 100644 drivers/video/st7735fb.h + +diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt +index 9de2b9f..54463a7 100644 +--- a/Documentation/devicetree/bindings/vendor-prefixes.txt ++++ b/Documentation/devicetree/bindings/vendor-prefixes.txt +@@ -4,6 +4,7 @@ This isn't an exhaustive list, but you should add new prefixes to it before + using them to avoid name-space collisions. + + ad Avionic Design GmbH ++adafruit Adafruit Industries + adi Analog Devices, Inc. + amcc Applied Micro Circuits Corporation (APM, formally AMCC) + apm Applied Micro Circuits Corporation (APM) +@@ -45,6 +46,7 @@ schindler Schindler + sil Silicon Image + simtek + sirf SiRF Technology, Inc. ++sitronix Sitronix Technology Corp. + st STMicroelectronics + stericsson ST-Ericsson + ti Texas Instruments +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index d08d799..9791d10 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -2417,6 +2417,17 @@ config FB_PUV3_UNIGFX + Choose this option if you want to use the Unigfx device as a + framebuffer device. Without the support of PCI & AGP. + ++config FB_ST7735 ++ tristate "ST7735 framebuffer support" ++ depends on FB && SPI ++ select FB_SYS_FILLRECT ++ select FB_SYS_COPYAREA ++ select FB_SYS_IMAGEBLIT ++ select FB_SYS_FOPS ++ select FB_DEFERRED_IO ++ help ++ Framebuffer support for the ST7735 display controller in SPI mode. ++ + source "drivers/video/omap/Kconfig" + source "drivers/video/omap2/Kconfig" + source "drivers/video/exynos/Kconfig" +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index 23e948e..0e13296 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -146,6 +146,7 @@ obj-$(CONFIG_FB_MSM) += msm/ + obj-$(CONFIG_FB_NUC900) += nuc900fb.o + obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o + obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o ++obj-$(CONFIG_FB_ST7735) += st7735fb.o + + # Platform or fallback drivers go here + obj-$(CONFIG_FB_UVESA) += uvesafb.o +diff --git a/drivers/video/st7735fb.c b/drivers/video/st7735fb.c +new file mode 100644 +index 0000000..67c2544 +--- /dev/null ++++ b/drivers/video/st7735fb.c +@@ -0,0 +1,631 @@ ++/* ++ * linux/drivers/video/st7735fb.c -- FB driver for ST7735 LCD controller ++ * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. ++ * ++ * Copyright (C) 2012, Matt Porter <matt@ohporter.com> ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/mm.h> ++#include <linux/vmalloc.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/fb.h> ++#include <linux/gpio.h> ++#include <linux/spi/spi.h> ++#include <linux/delay.h> ++#include <linux/err.h> ++#include <linux/uaccess.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_gpio.h> ++#include <linux/pinctrl/consumer.h> ++ ++#include "st7735fb.h" ++ ++static struct st7735_function st7735_cfg_script[] = { ++ { ST7735_START, ST7735_START}, ++ { ST7735_CMD, ST7735_SWRESET}, ++ { ST7735_DELAY, 150}, ++ { ST7735_CMD, ST7735_SLPOUT}, ++ { ST7735_DELAY, 500}, ++ { ST7735_CMD, ST7735_FRMCTR1}, ++ { ST7735_DATA, 0x01}, ++ { ST7735_DATA, 0x2c}, ++ { ST7735_DATA, 0x2d}, ++ { ST7735_CMD, ST7735_FRMCTR2}, ++ { ST7735_DATA, 0x01}, ++ { ST7735_DATA, 0x2c}, ++ { ST7735_DATA, 0x2d}, ++ { ST7735_CMD, ST7735_FRMCTR3}, ++ { ST7735_DATA, 0x01}, ++ { ST7735_DATA, 0x2c}, ++ { ST7735_DATA, 0x2d}, ++ { ST7735_DATA, 0x01}, ++ { ST7735_DATA, 0x2c}, ++ { ST7735_DATA, 0x2d}, ++ { ST7735_CMD, ST7735_INVCTR}, ++ { ST7735_DATA, 0x07}, ++ { ST7735_CMD, ST7735_PWCTR1}, ++ { ST7735_DATA, 0xa2}, ++ { ST7735_DATA, 0x02}, ++ { ST7735_DATA, 0x84}, ++ { ST7735_CMD, ST7735_PWCTR2}, ++ { ST7735_DATA, 0xc5}, ++ { ST7735_CMD, ST7735_PWCTR3}, ++ { ST7735_DATA, 0x0a}, ++ { ST7735_DATA, 0x00}, ++ { ST7735_CMD, ST7735_PWCTR4}, ++ { ST7735_DATA, 0x8a}, ++ { ST7735_DATA, 0x2a}, ++ { ST7735_CMD, ST7735_PWCTR5}, ++ { ST7735_DATA, 0x8a}, ++ { ST7735_DATA, 0xee}, ++ { ST7735_CMD, ST7735_VMCTR1}, ++ { ST7735_DATA, 0x0e}, ++ { ST7735_CMD, ST7735_INVOFF}, ++ { ST7735_CMD, ST7735_MADCTL}, ++ { ST7735_DATA, 0xc8}, ++ { ST7735_CMD, ST7735_COLMOD}, ++ { ST7735_DATA, 0x05}, ++ { ST7735_CMD, ST7735_CASET}, ++ { ST7735_DATA, 0x00}, ++ { ST7735_DATA, 0x00}, ++ { ST7735_DATA, 0x00}, ++ { ST7735_DATA, 0x00}, ++ { ST7735_DATA, 0x7f}, ++ { ST7735_CMD, ST7735_RASET}, ++ { ST7735_DATA, 0x00}, ++ { ST7735_DATA, 0x00}, ++ { ST7735_DATA, 0x00}, ++ { ST7735_DATA, 0x00}, ++ { ST7735_DATA, 0x9f}, ++ { ST7735_CMD, ST7735_GMCTRP1}, ++ { ST7735_DATA, 0x02}, ++ { ST7735_DATA, 0x1c}, ++ { ST7735_DATA, 0x07}, ++ { ST7735_DATA, 0x12}, ++ { ST7735_DATA, 0x37}, ++ { ST7735_DATA, 0x32}, ++ { ST7735_DATA, 0x29}, ++ { ST7735_DATA, 0x2d}, ++ { ST7735_DATA, 0x29}, ++ { ST7735_DATA, 0x25}, ++ { ST7735_DATA, 0x2b}, ++ { ST7735_DATA, 0x39}, ++ { ST7735_DATA, 0x00}, ++ { ST7735_DATA, 0x01}, ++ { ST7735_DATA, 0x03}, ++ { ST7735_DATA, 0x10}, ++ { ST7735_CMD, ST7735_GMCTRN1}, ++ { ST7735_DATA, 0x03}, ++ { ST7735_DATA, 0x1d}, ++ { ST7735_DATA, 0x07}, ++ { ST7735_DATA, 0x06}, ++ { ST7735_DATA, 0x2e}, ++ { ST7735_DATA, 0x2c}, ++ { ST7735_DATA, 0x29}, ++ { ST7735_DATA, 0x2d}, ++ { ST7735_DATA, 0x2e}, ++ { ST7735_DATA, 0x2e}, ++ { ST7735_DATA, 0x37}, ++ { ST7735_DATA, 0x3f}, ++ { ST7735_DATA, 0x00}, ++ { ST7735_DATA, 0x00}, ++ { ST7735_DATA, 0x02}, ++ { ST7735_DATA, 0x10}, ++ { ST7735_CMD, ST7735_DISPON}, ++ { ST7735_DELAY, 100}, ++ { ST7735_CMD, ST7735_NORON}, ++ { ST7735_DELAY, 10}, ++ { ST7735_END, ST7735_END}, ++}; ++ ++static struct fb_fix_screeninfo st7735fb_fix __devinitdata = { ++ .id = "ST7735", ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_DIRECTCOLOR, ++ .xpanstep = 0, ++ .ypanstep = 0, ++ .ywrapstep = 0, ++ .line_length = WIDTH*BPP/8, ++ .accel = FB_ACCEL_NONE, ++}; ++ ++static struct fb_var_screeninfo st7735fb_var __devinitdata = { ++ .xres = WIDTH, ++ .yres = HEIGHT, ++ .xres_virtual = WIDTH, ++ .yres_virtual = HEIGHT, ++ .bits_per_pixel = BPP, ++ .nonstd = 0, ++}; ++ ++static int st7735_write(struct st7735fb_par *par, u8 data) ++{ ++ par->buf[0] = data; ++ ++ return spi_write(par->spi, par->buf, 1); ++} ++ ++static void st7735_write_data(struct st7735fb_par *par, u8 data) ++{ ++ int ret = 0; ++ ++ /* Set data mode */ ++ gpio_set_value(par->dc, 1); ++ ++ ret = st7735_write(par, data); ++ if (ret < 0) ++ pr_err("%s: write data %02x failed with status %d\n", ++ par->info->fix.id, data, ret); ++} ++ ++static int st7735_write_data_buf(struct st7735fb_par *par, ++ u8 *txbuf, int size) ++{ ++ /* Set data mode */ ++ gpio_set_value(par->dc, 1); ++ ++ /* Write entire buffer */ ++ return spi_write(par->spi, txbuf, size); ++} ++ ++static void st7735_write_cmd(struct st7735fb_par *par, u8 data) ++{ ++ int ret = 0; ++ ++ /* Set command mode */ ++ gpio_set_value(par->dc, 0); ++ ++ ret = st7735_write(par, data); ++ if (ret < 0) ++ pr_err("%s: write command %02x failed with status %d\n", ++ par->info->fix.id, data, ret); ++} ++ ++static void st7735_run_cfg_script(struct st7735fb_par *par) ++{ ++ int i = 0; ++ int end_script = 0; ++ ++ do { ++ switch (st7735_cfg_script[i].cmd) ++ { ++ case ST7735_START: ++ break; ++ case ST7735_CMD: ++ st7735_write_cmd(par, ++ st7735_cfg_script[i].data & 0xff); ++ break; ++ case ST7735_DATA: ++ st7735_write_data(par, ++ st7735_cfg_script[i].data & 0xff); ++ break; ++ case ST7735_DELAY: ++ mdelay(st7735_cfg_script[i].data); ++ break; ++ case ST7735_END: ++ end_script = 1; ++ } ++ i++; ++ } while (!end_script); ++} ++ ++static void st7735_set_addr_win(struct st7735fb_par *par, ++ int xs, int ys, int xe, int ye) ++{ ++ st7735_write_cmd(par, ST7735_CASET); ++ st7735_write_data(par, 0x00); ++ st7735_write_data(par, xs + par->xoff); ++ st7735_write_data(par, 0x00); ++ st7735_write_data(par, xe + par->xoff); ++ st7735_write_cmd(par, ST7735_RASET); ++ st7735_write_data(par, 0x00); ++ st7735_write_data(par, ys + par->yoff); ++ st7735_write_data(par, 0x00); ++ st7735_write_data(par, ye + par->yoff); ++} ++ ++static void st7735_reset(struct st7735fb_par *par) ++{ ++ /* Reset controller */ ++ gpio_set_value(par->rst, 0); ++ udelay(10); ++ gpio_set_value(par->rst, 1); ++ mdelay(120); ++} ++ ++static void st7735fb_update_display(struct st7735fb_par *par) ++{ ++ int ret = 0; ++ u16 *vmem; ++#ifdef __LITTLE_ENDIAN ++ int i; ++ u16 *vmem16 = (u16 *)par->info->screen_base; ++ vmem = par->ssbuf; ++ ++ for (i=0; i<WIDTH*HEIGHT*BPP/8/2; i++) ++ vmem[i] = swab16(vmem16[i]); ++#else ++ vmem = (u16 *)par->info->screen_base; ++#endif ++ ++ mutex_lock(&(par->io_lock)); ++ ++ /* Set row/column data window */ ++ st7735_set_addr_win(par, 0, 0, WIDTH-1, HEIGHT-1); ++ ++ /* Internal RAM write command */ ++ st7735_write_cmd(par, ST7735_RAMWR); ++ ++ /* Blast framebuffer to ST7735 internal display RAM */ ++ ret = st7735_write_data_buf(par, (u8 *)vmem, WIDTH*HEIGHT*BPP/8); ++ if (ret < 0) ++ pr_err("%s: spi_write failed to update display buffer\n", ++ par->info->fix.id); ++ ++ mutex_unlock(&(par->io_lock)); ++} ++ ++static int st7735fb_init_display(struct st7735fb_par *par) ++{ ++ int ret = 0; ++ ++ /* Request GPIOs and initialize to default values */ ++ ret = gpio_request_one(par->rst, GPIOF_OUT_INIT_HIGH, ++ "ST7735 Reset Pin"); ++ if (ret < 0) { ++ pr_err("%s: failed to claim reset pin\n", par->info->fix.id); ++ goto out; ++ } ++ ret = gpio_request_one(par->dc, GPIOF_OUT_INIT_LOW, ++ "ST7735 Data/Command Pin"); ++ if (ret < 0) { ++ pr_err("%s: failed to claim data/command pin\n", par->info->fix.id); ++ goto out; ++ } ++ ++ st7735_reset(par); ++ ++ st7735_run_cfg_script(par); ++ ++out: ++ return ret; ++} ++ ++static void st7735fb_deferred_io(struct fb_info *info, ++ struct list_head *pagelist) ++{ ++ st7735fb_update_display(info->par); ++} ++ ++static void st7735fb_update_display_deferred(struct fb_info *info) ++{ ++ struct fb_deferred_io *fbdefio = info->fbdefio; ++ ++ schedule_delayed_work(&info->deferred_work, fbdefio->delay); ++} ++ ++static void st7735fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ++{ ++ sys_fillrect(info, rect); ++ ++ st7735fb_update_display_deferred(info); ++} ++ ++static void st7735fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) ++{ ++ sys_copyarea(info, area); ++ ++ st7735fb_update_display_deferred(info); ++} ++ ++static void st7735fb_imageblit(struct fb_info *info, const struct fb_image *image) ++{ ++ sys_imageblit(info, image); ++ ++ st7735fb_update_display_deferred(info); ++} ++ ++static ssize_t st7735fb_write(struct fb_info *info, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ unsigned long p = *ppos; ++ void *dst; ++ int err = 0; ++ unsigned long total_size; ++ ++ if (info->state != FBINFO_STATE_RUNNING) ++ return -EPERM; ++ ++ total_size = info->fix.smem_len; ++ ++ if (p > total_size) ++ return -EFBIG; ++ ++ if (count > total_size) { ++ err = -EFBIG; ++ count = total_size; ++ } ++ ++ if (count + p > total_size) { ++ if (!err) ++ err = -ENOSPC; ++ ++ count = total_size - p; ++ } ++ ++ dst = (void __force *) (info->screen_base + p); ++ ++ if (copy_from_user(dst, buf, count)) ++ err = -EFAULT; ++ ++ if (!err) ++ *ppos += count; ++ ++ st7735fb_update_display_deferred(info); ++ ++ return (err) ? err : count; ++} ++ ++static int st7735fb_setcolreg(unsigned regno, unsigned red, unsigned green, ++ unsigned blue, unsigned transp, ++ struct fb_info *info) ++{ ++ if (regno >= MAX_PALETTE) ++ return -EINVAL; ++ ++ /* RGB565 */ ++ ((u32*)(info->pseudo_palette))[regno] = ++ ((red & 0xf800) | ++ ((green & 0xfc00) >> 5) | ++ ((blue & 0xf800) >> 11)); ++ ++ return 0; ++} ++ ++static struct fb_ops st7735fb_ops = { ++ .owner = THIS_MODULE, ++ .fb_read = fb_sys_read, ++ .fb_write = st7735fb_write, ++ .fb_fillrect = st7735fb_fillrect, ++ .fb_copyarea = st7735fb_copyarea, ++ .fb_imageblit = st7735fb_imageblit, ++ .fb_setcolreg = st7735fb_setcolreg, ++}; ++ ++static struct fb_deferred_io st7735fb_defio = { ++ .delay = HZ/20, ++ .deferred_io = st7735fb_deferred_io, ++}; ++ ++static const struct spi_device_id st7735fb_device_id[] = { ++ { ++ .name = "tft-lcd-1.8-green", ++ .driver_data = ST7735_AF_TFT18_GREEN, ++ }, { ++ .name = "tft-lcd-1.8-red", ++ .driver_data = ST7735_AF_TFT18_RED, ++ }, { ++ /* sentinel */ ++ } ++}; ++MODULE_DEVICE_TABLE(spi, st7735fb_device_id); ++ ++static const struct of_device_id st7735fb_dt_ids[] = { ++ { .compatible = "adafruit,tft-lcd-1.8-green", .data = (void *) ST7735_AF_TFT18_GREEN, }, ++ { .compatible = "adafruit,tft-lcd-1.8-red", .data = (void *) ST7735_AF_TFT18_RED, }, ++}; ++MODULE_DEVICE_TABLE(of, st7735fb_dt_ids); ++ ++static int __devinit st7735fb_probe (struct spi_device *spi) ++{ ++ int vmem_size = WIDTH*HEIGHT*BPP/8; ++ u8 *vmem; ++ struct fb_info *info; ++ struct st7735fb_par *par; ++ int retval = -ENOMEM; ++ struct device_node *np = spi->dev.of_node; ++ const struct spi_device_id *spi_id = spi_get_device_id(spi); ++ struct pinctrl *pinctrl; ++ ++ if (!spi_id) { ++ dev_err(&spi->dev, ++ "device id not supported!\n"); ++ return -EINVAL; ++ } ++ ++ pinctrl = devm_pinctrl_get_select_default(&spi->dev); ++ if (IS_ERR(pinctrl)) ++ dev_warn(&spi->dev, ++ "pins are not configured from the driver\n"); ++ ++#ifdef __LITTLE_ENDIAN ++ vmem = (u8 *)vmalloc(vmem_size); ++#else ++ vmem = (u8 *)kmalloc(vmem_size, GFP_KERNEL); ++#endif ++ if (!vmem) ++ return retval; ++ ++ info = framebuffer_alloc(sizeof(struct st7735fb_par), &spi->dev); ++ if (!info) ++ goto fballoc_fail; ++ ++ info->pseudo_palette = kmalloc(sizeof(u32)*MAX_PALETTE, GFP_KERNEL); ++ if (!info->pseudo_palette) { ++ goto palette_fail; ++ } ++ ++ info->screen_base = (u8 __force __iomem *)vmem; ++ info->fbops = &st7735fb_ops; ++ info->fix = st7735fb_fix; ++ info->fix.smem_len = vmem_size; ++ info->var = st7735fb_var; ++ /* Choose any packed pixel format as long as it's 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; ++ ++ info->fbdefio = &st7735fb_defio; ++ fb_deferred_io_init(info); ++ ++ retval = fb_alloc_cmap(&info->cmap, MAX_PALETTE, 0); ++ if (retval < 0) ++ goto cmap_fail; ++ info->cmap.len = MAX_PALETTE; ++ ++ par = info->par; ++ par->info = info; ++ par->spi = spi; ++ ++ mutex_init(&par->io_lock); ++ ++ if (spi_id->driver_data == ST7735_AF_TFT18_GREEN) { ++ par->xoff = 2; ++ par->yoff = 1; ++ } else { ++ par->xoff = 0; ++ par->yoff = 0; ++ } ++ ++ /* TODO: fix all exit paths for cleanup */ ++ par->rst = of_get_named_gpio(np, "st7735-rst", 0); ++ if (par->rst < 0) { ++ printk("failed to find st7735-rst node!\n"); ++ return -EINVAL; ++ } ++ ++ par->dc = of_get_named_gpio(np, "st7735-dc", 0); ++ if (par->dc < 0) { ++ printk("failed to find st7735-dc node!\n"); ++ return -EINVAL; ++ } ++ ++ par->buf = kmalloc(1, GFP_KERNEL); ++ if (!par->buf) { ++ retval = -ENOMEM; ++ goto buf_fail; ++ } ++ ++#ifdef __LITTLE_ENDIAN ++ /* Allocated swapped shadow buffer */ ++ par->ssbuf = kmalloc(vmem_size, GFP_KERNEL); ++ if (!par->ssbuf) { ++ retval = -ENOMEM; ++ goto ssbuf_fail; ++ } ++#endif ++ ++ retval = st7735fb_init_display(par); ++ if (retval < 0) ++ goto init_fail; ++ ++ retval = register_framebuffer(info); ++ if (retval < 0) ++ goto fbreg_fail; ++ ++ spi_set_drvdata(spi, info); ++ ++ printk(KERN_INFO ++ "fb%d: %s frame buffer device,\n\tusing %d KiB of video memory\n", ++ info->node, info->fix.id, vmem_size); ++ ++ return 0; ++ ++ ++ spi_set_drvdata(spi, NULL); ++ ++fbreg_fail: ++ /* TODO: release gpios on fail */ ++ /* TODO: and unwind everything in init */ ++ ++init_fail: ++#ifdef __LITTLE_ENDIAN ++ kfree(par->ssbuf); ++#endif ++ ++ssbuf_fail: ++ kfree(par->buf); ++ ++buf_fail: ++ fb_dealloc_cmap(&info->cmap); ++ ++cmap_fail: ++ kfree(info->pseudo_palette); ++ ++palette_fail: ++ framebuffer_release(info); ++ ++fballoc_fail: ++#ifdef __LITTLE_ENDIAN ++ vfree(vmem); ++#else ++ kfree(vmem); ++#endif ++ ++ return retval; ++} ++ ++static int __devexit st7735fb_remove(struct spi_device *spi) ++{ ++ struct fb_info *info = spi_get_drvdata(spi); ++ ++ spi_set_drvdata(spi, NULL); ++ ++ if (info) { ++ unregister_framebuffer(info); ++ fb_dealloc_cmap(&info->cmap); ++ kfree(info->pseudo_palette); ++ vfree(info->screen_base); ++ framebuffer_release(info); ++ } ++ ++ /* TODO: release gpios */ ++ ++ return 0; ++} ++ ++static struct spi_driver st7735fb_driver = { ++ .id_table = st7735fb_device_id, ++ .driver = { ++ .name = "st7735", ++ .owner = THIS_MODULE, ++ .of_match_table = st7735fb_dt_ids, ++ }, ++ .probe = st7735fb_probe, ++ .remove = __devexit_p(st7735fb_remove), ++}; ++ ++static int __init st7735fb_init(void) ++{ ++ return spi_register_driver(&st7735fb_driver); ++} ++ ++static void __exit st7735fb_exit(void) ++{ ++ spi_unregister_driver(&st7735fb_driver); ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++module_init(st7735fb_init); ++module_exit(st7735fb_exit); ++ ++MODULE_DESCRIPTION("FB driver for ST7735 display controller"); ++MODULE_AUTHOR("Matt Porter <matt@ohporter.com>"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/st7735fb.h b/drivers/video/st7735fb.h +new file mode 100644 +index 0000000..0ce5c11 +--- /dev/null ++++ b/drivers/video/st7735fb.h +@@ -0,0 +1,84 @@ ++/* ++ * linux/include/video/st7735fb.h -- FB driver for ST7735 LCD controller ++ * ++ * Copyright (C) 2012, Matt Porter ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ */ ++ ++#define DRVNAME "st7735fb" ++#define WIDTH 128 ++#define HEIGHT 160 ++#define BPP 16 ++#define MAX_PALETTE 16 ++ ++/* Supported display modules */ ++#define ST7735_AF_TFT18_GREEN 0 /* Adafruit SPI TFT 1.8" - green tab */ ++#define ST7735_AF_TFT18_RED 1 /* Adafruit SPI TFT 1.8" - red tab */ ++ ++/* Init script function */ ++struct st7735_function { ++ u16 cmd; ++ u16 data; ++}; ++ ++/* Init script commands */ ++enum st7735_cmd { ++ ST7735_START, ++ ST7735_END, ++ ST7735_CMD, ++ ST7735_DATA, ++ ST7735_DELAY ++}; ++ ++struct st7735fb_par { ++ struct spi_device *spi; ++ struct fb_info *info; ++ struct mutex io_lock; ++ int xoff; ++ int yoff; ++ int rst; ++ int dc; ++ u16 *ssbuf; ++ u8 *buf; ++}; ++ ++/* ST7735 Commands */ ++#define ST7735_NOP 0x0 ++#define ST7735_SWRESET 0x01 ++#define ST7735_RDDID 0x04 ++#define ST7735_RDDST 0x09 ++#define ST7735_SLPIN 0x10 ++#define ST7735_SLPOUT 0x11 ++#define ST7735_PTLON 0x12 ++#define ST7735_NORON 0x13 ++#define ST7735_INVOFF 0x20 ++#define ST7735_INVON 0x21 ++#define ST7735_DISPOFF 0x28 ++#define ST7735_DISPON 0x29 ++#define ST7735_CASET 0x2A ++#define ST7735_RASET 0x2B ++#define ST7735_RAMWR 0x2C ++#define ST7735_RAMRD 0x2E ++#define ST7735_COLMOD 0x3A ++#define ST7735_MADCTL 0x36 ++#define ST7735_FRMCTR1 0xB1 ++#define ST7735_FRMCTR2 0xB2 ++#define ST7735_FRMCTR3 0xB3 ++#define ST7735_INVCTR 0xB4 ++#define ST7735_DISSET5 0xB6 ++#define ST7735_PWCTR1 0xC0 ++#define ST7735_PWCTR2 0xC1 ++#define ST7735_PWCTR3 0xC2 ++#define ST7735_PWCTR4 0xC3 ++#define ST7735_PWCTR5 0xC4 ++#define ST7735_VMCTR1 0xC5 ++#define ST7735_RDID1 0xDA ++#define ST7735_RDID2 0xDB ++#define ST7735_RDID3 0xDC ++#define ST7735_RDID4 0xDD ++#define ST7735_GMCTRP1 0xE0 ++#define ST7735_GMCTRN1 0xE1 ++#define ST7735_PWCTR6 0xFC diff --git a/patches/linux-3.7-rc6/0002-regulator-tps65910-fix-BUG_ON-shown-with-vrtc-regula.patch b/patches/linux-3.7-rc6/0002-regulator-tps65910-fix-BUG_ON-shown-with-vrtc-regula.patch new file mode 100644 index 0000000..d96dd9b --- /dev/null +++ b/patches/linux-3.7-rc6/0002-regulator-tps65910-fix-BUG_ON-shown-with-vrtc-regula.patch @@ -0,0 +1,41 @@ +From 99ab21ddea0d88d7d60a2210c0aa7c582571fb5b Mon Sep 17 00:00:00 2001 +From: "AnilKumar, Chimata" <anilkumar@ti.com> +Date: Mon, 15 Oct 2012 12:15:58 +0000 +Subject: [PATCH] regulator: tps65910: fix BUG_ON() shown with vrtc regulator + +Fix BUG_ON() error if tps65910 VRTC regulator is used with out +rdev->desc->volt_table data. Recent changes in regulator core driver +which add support for "regulator_list_voltage_table" have BUG_ON() if +regulator descriptor do not voltage table information. This patch adds +the voltage table information to fix the issue. + +Signed-off-by: AnilKumar Ch <anilkumar@ti.com> +--- + drivers/regulator/tps65910-regulator.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c +index 793adda..1d2dd18 100644 +--- a/drivers/regulator/tps65910-regulator.c ++++ b/drivers/regulator/tps65910-regulator.c +@@ -38,6 +38,11 @@ static const unsigned int VIO_VSEL_table[] = { + + /* VSEL tables for TPS65910 specific LDOs and dcdc's */ + ++/* supported VRTC voltages in microvolts */ ++static const unsigned int VRTC_VSEL_table[] = { ++ 1800000, ++}; ++ + /* supported VDD3 voltages in microvolts */ + static const unsigned int VDD3_VSEL_table[] = { + 5000000, +@@ -95,6 +100,8 @@ static struct tps_info tps65910_regs[] = { + { + .name = "vrtc", + .vin_name = "vcc7", ++ .n_voltages = ARRAY_SIZE(VRTC_VSEL_table), ++ .voltage_table = VRTC_VSEL_table, + .enable_time_us = 2200, + }, + { diff --git a/patches/linux-3.7-rc6/0003-dmaengine-add-helper-function-to-request-a-slave-DMA.patch b/patches/linux-3.7-rc6/0003-dmaengine-add-helper-function-to-request-a-slave-DMA.patch new file mode 100644 index 0000000..78b2693 --- /dev/null +++ b/patches/linux-3.7-rc6/0003-dmaengine-add-helper-function-to-request-a-slave-DMA.patch @@ -0,0 +1,94 @@ +From 510f4fd7a8ba825a4b376c27ba86fa5b976fb974 Mon Sep 17 00:00:00 2001 +From: Jon Hunter <jon-hunter@ti.com> +Date: Fri, 14 Sep 2012 17:41:57 -0500 +Subject: [PATCH] dmaengine: add helper function to request a slave DMA + channel + +Currently slave DMA channels are requested by calling dma_request_channel() +and requires DMA clients to pass various filter parameters to obtain the +appropriate channel. + +With device-tree being used by architectures such as arm and the addition of +device-tree helper functions to extract the relevant DMA client information +from device-tree, add a new function to request a slave DMA channel using +device-tree. This function is currently a simple wrapper that calls the +device-tree of_dma_request_slave_channel() function. + +Cc: Nicolas Ferre <nicolas.ferre@atmel.com> +Cc: Benoit Cousson <b-cousson@ti.com> +Cc: Stephen Warren <swarren@nvidia.com> +Cc: Grant Likely <grant.likely@secretlab.ca> +Cc: Russell King <linux@arm.linux.org.uk> +Cc: Rob Herring <rob.herring@calxeda.com> +Cc: Arnd Bergmann <arnd@arndb.de> +Cc: Vinod Koul <vinod.koul@intel.com> +Cc: Dan Williams <djbw@fb.com> + +Acked-by: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Jon Hunter <jon-hunter@ti.com> +Reviewed-by: Stephen Warren <swarren@wwwdotorg.org> +Acked-by: Rob Herring <rob.herring@calxeda.com> +Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com> +--- + drivers/dma/dmaengine.c | 16 ++++++++++++++++ + include/linux/dmaengine.h | 6 ++++++ + 2 files changed, 22 insertions(+) + +diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c +index a815d44..d37cf95 100644 +--- a/drivers/dma/dmaengine.c ++++ b/drivers/dma/dmaengine.c +@@ -62,6 +62,7 @@ + #include <linux/rculist.h> + #include <linux/idr.h> + #include <linux/slab.h> ++#include <linux/of_dma.h> + + static DEFINE_MUTEX(dma_list_mutex); + static DEFINE_IDR(dma_idr); +@@ -546,6 +547,21 @@ struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, v + } + EXPORT_SYMBOL_GPL(__dma_request_channel); + ++/** ++ * dma_request_slave_channel - try to allocate an exclusive slave channel ++ * @dev: pointer to client device structure ++ * @name: slave channel name ++ */ ++struct dma_chan *dma_request_slave_channel(struct device *dev, char *name) ++{ ++ /* If device-tree is present get slave info from here */ ++ if (dev->of_node) ++ return of_dma_request_slave_channel(dev->of_node, name); ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(dma_request_slave_channel); ++ + void dma_release_channel(struct dma_chan *chan) + { + mutex_lock(&dma_list_mutex); +diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h +index d3201e4..8cd0e25 100644 +--- a/include/linux/dmaengine.h ++++ b/include/linux/dmaengine.h +@@ -974,6 +974,7 @@ enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie); + enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx); + void dma_issue_pending_all(void); + struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param); ++struct dma_chan *dma_request_slave_channel(struct device *dev, char *name); + void dma_release_channel(struct dma_chan *chan); + #else + static inline enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx) +@@ -988,6 +989,11 @@ static inline struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, + { + return NULL; + } ++static inline struct dma_chan *dma_request_slave_channel(struct device *dev, ++ char *name) ++{ ++ return NULL ++} + static inline void dma_release_channel(struct dma_chan *chan) + { + } diff --git a/patches/linux-3.7-rc6/0004-of-Add-generic-device-tree-DMA-helpers.patch b/patches/linux-3.7-rc6/0004-of-Add-generic-device-tree-DMA-helpers.patch new file mode 100644 index 0000000..fb08560 --- /dev/null +++ b/patches/linux-3.7-rc6/0004-of-Add-generic-device-tree-DMA-helpers.patch @@ -0,0 +1,533 @@ +From 21793273a36ca45c4162f41978a3ec8eb1984c42 Mon Sep 17 00:00:00 2001 +From: Jon Hunter <jon-hunter@ti.com> +Date: Fri, 14 Sep 2012 17:41:56 -0500 +Subject: [PATCH] of: Add generic device tree DMA helpers + +This is based upon the work by Benoit Cousson [1] and Nicolas Ferre [2] +to add some basic helpers to retrieve a DMA controller device_node and the +DMA request/channel information. + +Aim of DMA helpers +- The purpose of device-tree is to describe the capabilites of the hardware. + Thinking about DMA controllers purely from the context of the hardware to + begin with, we can describe a device in terms of a DMA controller as + follows ... + 1. Number of DMA controllers + 2. Number of channels (maybe physical or logical) + 3. Mapping of DMA requests signals to DMA controller + 4. Number of DMA interrupts + 5. Mapping of DMA interrupts to channels +- With the above in mind the aim of the DT DMA helper functions is to extract + the above information from the DT and provide to the appropriate driver. + However, due to the vast number of DMA controllers and not all are using a + common driver (such as DMA Engine) it has been seen that this is not a + trivial task. In previous discussions on this topic the following concerns + have been raised ... + 1. How does the binding support devices with multiple DMA controllers? + 2. How to support both legacy DMA controllers not using DMA Engine as + well as those that support DMA Engine. + 3. When using with DMA Engine how do we support the various + implementations where the opaque filter function parameter differs + between implementations? + 4. How do we handle DMA channels that are identified with a string + versus a integer? +- Hence the design of the DMA helpers has to accomodate the above or align on + an agreement what can be or should be supported. + +Design of DMA helpers + +1. Registering DMA controllers + + In the case of DMA controllers that are using DMA Engine, requesting a + channel is performed by calling the following function. + + struct dma_chan *dma_request_channel(dma_cap_mask_t mask, + dma_filter_fn filter_fn, + void *filter_param); + + The mask variable is used to match a type of the device controller in a list + of controllers. The filter_fn and filter_param are used to identify the + required dma channel and return a handle to the dma channel of type dma_chan. + + From the examples I have seen, the mask and filter_fn are constant + for a given DMA controller and therefore, we can specify these as controller + specific data when registering the DMA controller with the device-tree DMA + helpers. + + The filter_param variable is of an unknown type and is typically specific + to the DMA engine implementation for a given DMA controller. To allow some + flexibility in the type and formating of this filter_param we employ an + xlate to translate the device-tree binding information into the appropriate + format. The xlate function used for a DMA controller can also be specified + when registering the DMA controller with the device-tree DMA helpers. + + Based upon the above, a function for registering the DMA controller with the + DMA helpers now looks like the below. The data variable is used to pass a + pointer to DMA controller specific data used by the xlate function. + + int of_dma_controller_register(struct device_node *np, + struct dma_chan *(*of_dma_xlate) + (struct of_phandle_args *, struct of_dma *), + void *data) + + For example, in the case where DMA engine is used, we define the following + structure (that stores the DMA engine capability mask and filter function) + and pass this to the data variable in the above function. + + struct of_dma_filter_info { + dma_cap_mask_t dma_cap; + dma_filter_fn filter_fn; + }; + +2. Representing and requesting channel information + + Please see the dma binding documentation included in this patch for a + description of how DMA controllers and client information should be + represented with device-tree. For more information on how this binding + came about please see [3]. In addition to this, feedback received from + the Linux kernel summit showed a consensus (among those who attended) to + use a name to identify DMA client information [4]. + + A DMA channel can be requested by calling the following function, where name + is a required parameter used for identifying a DMA channel. This function + has been designed to return a structure of type dma_chan to work with the + DMA engine driver. Note that if DMA engine is used then drivers should be + using the DMA engine API dma_request_slave_channel() (implemented in part 2 + of this series, "dmaengine: add helper function to request a slave DMA + channel") which will in turn call the below function if device-tree is + present. The aim being to have a common DMA engine interface regardless of + whether device tree is being used. + + struct dma_chan *of_dma_request_slave_channel(struct device_node *np, + char *name) + +3. Supporting legacy devices not using DMA Engine + + These devices present a problem, as there may not be a uniform way to easily + support them with regard to device tree. Ideally, these should be migrated + to DMA engine. However, if this is not possible, then they should still be + able to use this binding, the only constaint imposed by this implementation + is that when requesting a DMA channel via of_dma_request_slave_channel(), it + will return a type of dma_chan. + +This implementation has been tested on OMAP4430 using the kernel v3.6-rc5. I +have validated that MMC is working on the PANDA board with this implementation. +My development branch for testing on OMAP can be found here [5]. + +v6: - minor corrections in DMA binding documentation +v5: - minor update to binding documentation + - added loop to exhaustively search for a slave channel in the case where + there could be alternative channels available +v4: - revert the removal of xlate function from v3 + - update the proposed binding format and APIs based upon discussions [3] +v3: - avoid passing an xlate function and instead pass DMA engine parameters + - define number of dma channels and requests in dma-controller node +v2: - remove of_dma_to_resource API + - make property #dma-cells required (no fallback anymore) + - another check in of_dma_xlate_onenumbercell() function + +[1] http://article.gmane.org/gmane.linux.drivers.devicetree/12022 +[2] http://article.gmane.org/gmane.linux.ports.arm.omap/73622 +[3] http://marc.info/?l=linux-omap&m=133582085008539&w=2 +[4] http://pad.linaro.org/arm-mini-summit-2012 +[5] https://github.com/jonhunter/linux/tree/dev-dt-dma + +Cc: Nicolas Ferre <nicolas.ferre@atmel.com> +Cc: Benoit Cousson <b-cousson@ti.com> +Cc: Stephen Warren <swarren@nvidia.com> +Cc: Grant Likely <grant.likely@secretlab.ca> +Cc: Russell King <linux@arm.linux.org.uk> +Cc: Rob Herring <rob.herring@calxeda.com> +Cc: Arnd Bergmann <arnd@arndb.de> +Cc: Vinod Koul <vinod.koul@intel.com> +Cc: Dan Williams <djbw@fb.com> + +Reviewed-by: Arnd Bergmann <arnd@arndb.de> +Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Jon Hunter <jon-hunter@ti.com> +Reviewed-by: Stephen Warren <swarren@wwwdotorg.org> +Acked-by: Rob Herring <rob.herring@calxeda.com> +Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com> +--- + Documentation/devicetree/bindings/dma/dma.txt | 81 +++++++++ + drivers/of/Makefile | 2 +- + drivers/of/dma.c | 219 +++++++++++++++++++++++++ + include/linux/of_dma.h | 45 +++++ + 4 files changed, 346 insertions(+), 1 deletion(-) + create mode 100644 Documentation/devicetree/bindings/dma/dma.txt + create mode 100644 drivers/of/dma.c + create mode 100644 include/linux/of_dma.h + +diff --git a/Documentation/devicetree/bindings/dma/dma.txt b/Documentation/devicetree/bindings/dma/dma.txt +new file mode 100644 +index 0000000..a4f59a5 +--- /dev/null ++++ b/Documentation/devicetree/bindings/dma/dma.txt +@@ -0,0 +1,81 @@ ++* Generic DMA Controller and DMA request bindings ++ ++Generic binding to provide a way for a driver using DMA Engine to retrieve the ++DMA request or channel information that goes from a hardware device to a DMA ++controller. ++ ++ ++* DMA controller ++ ++Required property: ++- #dma-cells: Must be at least 1. Used to provide DMA controller ++ specific information. See DMA client binding below for ++ more details. ++ ++Optional properties: ++- #dma-channels: Number of DMA channels supported by the controller. ++- #dma-requests: Number of DMA requests signals supported by the ++ controller. ++ ++Example: ++ ++ dma: dma@48000000 { ++ compatible = "ti,omap-sdma" ++ reg = <0x48000000 0x1000>; ++ interrupts = <0 12 0x4 ++ 0 13 0x4 ++ 0 14 0x4 ++ 0 15 0x4>; ++ #dma-cells = <1>; ++ #dma-channels = <32>; ++ #dma-requests = <127>; ++ }; ++ ++ ++* DMA client ++ ++Client drivers should specify the DMA property using a phandle to the controller ++followed by DMA controller specific data. ++ ++Required property: ++- dmas: List of one or more DMA specifiers, each consisting of ++ - A phandle pointing to DMA controller node ++ - A number of integer cells, as determined by the ++ #dma-cells property in the node referenced by phandle ++ containing DMA controller specific information. This ++ typically contains a DMA request line number or a ++ channel number, but can contain any data that is used ++ required for configuring a channel. ++- dma-names: Contains one identifier string for each DMA specifier in ++ the dmas property. The specific strings that can be used ++ are defined in the binding of the DMA client device. ++ Multiple DMA specifiers can be used to represent ++ alternatives and in this case the dma-names for those ++ DMA specifiers must be identical (see examples). ++ ++Examples: ++ ++1. A device with one DMA read channel, one DMA write channel: ++ ++ i2c1: i2c@1 { ++ ... ++ dmas = <&dma 2 /* read channel */ ++ &dma 3>; /* write channel */ ++ dma-names = "rx", "tx" ++ ... ++ }; ++ ++2. A single read-write channel with three alternative DMA controllers: ++ ++ dmas = <&dma1 5 ++ &dma2 7 ++ &dma3 2>; ++ dma-names = "rx-tx", "rx-tx", "rx-tx" ++ ++3. A device with three channels, one of which has two alternatives: ++ ++ dmas = <&dma1 2 /* read channel */ ++ &dma1 3 /* write channel */ ++ &dma2 0 /* error read */ ++ &dma3 0>; /* alternative error read */ ++ dma-names = "rx", "tx", "error", "error"; +diff --git a/drivers/of/Makefile b/drivers/of/Makefile +index e027f44..eafa107 100644 +--- a/drivers/of/Makefile ++++ b/drivers/of/Makefile +@@ -1,4 +1,4 @@ +-obj-y = base.o ++obj-y = base.o dma.o + obj-$(CONFIG_OF_FLATTREE) += fdt.o + obj-$(CONFIG_OF_PROMTREE) += pdt.o + obj-$(CONFIG_OF_ADDRESS) += address.o +diff --git a/drivers/of/dma.c b/drivers/of/dma.c +new file mode 100644 +index 0000000..19ad37c +--- /dev/null ++++ b/drivers/of/dma.c +@@ -0,0 +1,219 @@ ++/* ++ * Device tree helpers for DMA request / controller ++ * ++ * Based on of_gpio.c ++ * ++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/device.h> ++#include <linux/err.h> ++#include <linux/module.h> ++#include <linux/rculist.h> ++#include <linux/slab.h> ++#include <linux/of.h> ++#include <linux/of_dma.h> ++ ++static LIST_HEAD(of_dma_list); ++ ++/** ++ * of_dma_find_controller - Find a DMA controller in DT DMA helpers list ++ * @np: device node of DMA controller ++ */ ++static struct of_dma *of_dma_find_controller(struct device_node *np) ++{ ++ struct of_dma *ofdma; ++ ++ if (list_empty(&of_dma_list)) { ++ pr_err("empty DMA controller list\n"); ++ return NULL; ++ } ++ ++ list_for_each_entry_rcu(ofdma, &of_dma_list, of_dma_controllers) ++ if (ofdma->of_node == np) ++ return ofdma; ++ ++ return NULL; ++} ++ ++/** ++ * of_dma_controller_register - Register a DMA controller to DT DMA helpers ++ * @np: device node of DMA controller ++ * @of_dma_xlate: translation function which converts a phandle ++ * arguments list into a dma_chan structure ++ * @data pointer to controller specific data to be used by ++ * translation function ++ * ++ * Returns 0 on success or appropriate errno value on error. ++ * ++ * Allocated memory should be freed with appropriate of_dma_controller_free() ++ * call. ++ */ ++int of_dma_controller_register(struct device_node *np, ++ struct dma_chan *(*of_dma_xlate) ++ (struct of_phandle_args *, struct of_dma *), ++ void *data) ++{ ++ struct of_dma *ofdma; ++ int nbcells; ++ ++ if (!np || !of_dma_xlate) { ++ pr_err("%s: not enough information provided\n", __func__); ++ return -EINVAL; ++ } ++ ++ ofdma = kzalloc(sizeof(*ofdma), GFP_KERNEL); ++ if (!ofdma) ++ return -ENOMEM; ++ ++ nbcells = be32_to_cpup(of_get_property(np, "#dma-cells", NULL)); ++ if (!nbcells) { ++ pr_err("%s: #dma-cells property is missing or invalid\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ ofdma->of_node = np; ++ ofdma->of_dma_nbcells = nbcells; ++ ofdma->of_dma_xlate = of_dma_xlate; ++ ofdma->of_dma_data = data; ++ ++ /* Now queue of_dma controller structure in list */ ++ list_add_tail_rcu(&ofdma->of_dma_controllers, &of_dma_list); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(of_dma_controller_register); ++ ++/** ++ * of_dma_controller_free - Remove a DMA controller from DT DMA helpers list ++ * @np: device node of DMA controller ++ * ++ * Memory allocated by of_dma_controller_register() is freed here. ++ */ ++void of_dma_controller_free(struct device_node *np) ++{ ++ struct of_dma *ofdma; ++ ++ ofdma = of_dma_find_controller(np); ++ if (ofdma) { ++ list_del_rcu(&ofdma->of_dma_controllers); ++ kfree(ofdma); ++ } ++} ++EXPORT_SYMBOL_GPL(of_dma_controller_free); ++ ++/** ++ * of_dma_find_channel - Find a DMA channel by name ++ * @np: device node to look for DMA channels ++ * @name: name of desired channel ++ * @dma_spec: pointer to DMA specifier as found in the device tree ++ * ++ * Find a DMA channel by the name. Returns 0 on success or appropriate ++ * errno value on error. ++ */ ++static int of_dma_find_channel(struct device_node *np, char *name, ++ struct of_phandle_args *dma_spec) ++{ ++ int count, i; ++ const char *s; ++ ++ count = of_property_count_strings(np, "dma-names"); ++ if (count < 0) ++ return count; ++ ++ for (i = 0; i < count; i++) { ++ if (of_property_read_string_index(np, "dma-names", i, &s)) ++ continue; ++ ++ if (strcmp(name, s)) ++ continue; ++ ++ if (!of_parse_phandle_with_args(np, "dmas", "#dma-cells", i, ++ dma_spec)) ++ return 0; ++ } ++ ++ return -ENODEV; ++} ++ ++/** ++ * of_dma_request_slave_channel - Get the DMA slave channel ++ * @np: device node to get DMA request from ++ * @name: name of desired channel ++ * ++ * Returns pointer to appropriate dma channel on success or NULL on error. ++ */ ++struct dma_chan *of_dma_request_slave_channel(struct device_node *np, ++ char *name) ++{ ++ struct of_phandle_args dma_spec; ++ struct of_dma *ofdma; ++ struct dma_chan *chan; ++ int r; ++ ++ if (!np || !name) { ++ pr_err("%s: not enough information provided\n", __func__); ++ return NULL; ++ } ++ ++ do { ++ r = of_dma_find_channel(np, name, &dma_spec); ++ if (r) { ++ pr_err("%s: can't find DMA channel\n", np->full_name); ++ return NULL; ++ } ++ ++ ofdma = of_dma_find_controller(dma_spec.np); ++ if (!ofdma) { ++ pr_debug("%s: can't find DMA controller %s\n", ++ np->full_name, dma_spec.np->full_name); ++ continue; ++ } ++ ++ if (dma_spec.args_count != ofdma->of_dma_nbcells) { ++ pr_debug("%s: wrong #dma-cells for %s\n", np->full_name, ++ dma_spec.np->full_name); ++ continue; ++ } ++ ++ chan = ofdma->of_dma_xlate(&dma_spec, ofdma); ++ ++ of_node_put(dma_spec.np); ++ ++ } while (!chan); ++ ++ return chan; ++} ++ ++/** ++ * of_dma_simple_xlate - Simple DMA engine translation function ++ * @dma_spec: pointer to DMA specifier as found in the device tree ++ * @of_dma: pointer to DMA controller data ++ * ++ * A simple translation function for devices that use a 32-bit value for the ++ * filter_param when calling the DMA engine dma_request_channel() function. ++ * Note that this translation function requires that #dma-cells is equal to 1 ++ * and the argument of the dma specifier is the 32-bit filter_param. Returns ++ * pointer to appropriate dma channel on success or NULL on error. ++ */ ++struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec, ++ struct of_dma *ofdma) ++{ ++ int count = dma_spec->args_count; ++ struct of_dma_filter_info *info = ofdma->of_dma_data; ++ ++ if (!info || !info->filter_fn) ++ return NULL; ++ ++ if (count != 1) ++ return NULL; ++ ++ return dma_request_channel(info->dma_cap, info->filter_fn, ++ &dma_spec->args[0]); ++} ++EXPORT_SYMBOL_GPL(of_dma_simple_xlate); +diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h +new file mode 100644 +index 0000000..337823d +--- /dev/null ++++ b/include/linux/of_dma.h +@@ -0,0 +1,45 @@ ++/* ++ * OF helpers for DMA request / controller ++ * ++ * Based on of_gpio.h ++ * ++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __LINUX_OF_DMA_H ++#define __LINUX_OF_DMA_H ++ ++#include <linux/of.h> ++#include <linux/dmaengine.h> ++ ++struct device_node; ++ ++struct of_dma { ++ struct list_head of_dma_controllers; ++ struct device_node *of_node; ++ int of_dma_nbcells; ++ struct dma_chan *(*of_dma_xlate) ++ (struct of_phandle_args *, struct of_dma *); ++ void *of_dma_data; ++}; ++ ++struct of_dma_filter_info { ++ dma_cap_mask_t dma_cap; ++ dma_filter_fn filter_fn; ++}; ++ ++extern int of_dma_controller_register(struct device_node *np, ++ struct dma_chan *(*of_dma_xlate) ++ (struct of_phandle_args *, struct of_dma *), ++ void *data); ++extern void of_dma_controller_free(struct device_node *np); ++extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np, ++ char *name); ++extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec, ++ struct of_dma *ofdma); ++ ++#endif /* __LINUX_OF_DMA_H */ diff --git a/patches/linux-3.7-rc6/0005-of-dma-fix-build-break-for-CONFIG_OF.patch b/patches/linux-3.7-rc6/0005-of-dma-fix-build-break-for-CONFIG_OF.patch new file mode 100644 index 0000000..1801a9c --- /dev/null +++ b/patches/linux-3.7-rc6/0005-of-dma-fix-build-break-for-CONFIG_OF.patch @@ -0,0 +1,54 @@ +From 7ea168ca4862bc9a803bfd9e1415c1b71f6349e0 Mon Sep 17 00:00:00 2001 +From: Vinod Koul <vinod.koul@linux.intel.com> +Date: Tue, 25 Sep 2012 09:57:36 +0530 +Subject: [PATCH] of: dma- fix build break for !CONFIG_OF + +Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com> +--- + include/linux/of_dma.h | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h +index 337823d..67158dd 100644 +--- a/include/linux/of_dma.h ++++ b/include/linux/of_dma.h +@@ -32,6 +32,7 @@ struct of_dma_filter_info { + dma_filter_fn filter_fn; + }; + ++#ifdef CONFIG_OF + extern int of_dma_controller_register(struct device_node *np, + struct dma_chan *(*of_dma_xlate) + (struct of_phandle_args *, struct of_dma *), +@@ -41,5 +42,31 @@ extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np, + char *name); + extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma); ++#else ++static int of_dma_controller_register(struct device_node *np, ++ struct dma_chan *(*of_dma_xlate) ++ (struct of_phandle_args *, struct of_dma *), ++ void *data) ++{ ++ return -ENODEV; ++} ++ ++static void of_dma_controller_free(struct device_node *np) ++{ ++} ++ ++static struct dma_chan *of_dma_request_slave_channel(struct device_node *np, ++ char *name) ++{ ++ return NULL; ++} ++ ++static struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec, ++ struct of_dma *ofdma) ++{ ++ return NULL; ++} ++ ++#endif + + #endif /* __LINUX_OF_DMA_H */ diff --git a/patches/linux-3.7-rc6/0006-of-dma-fix-typos-in-generic-dma-binding-definition.patch b/patches/linux-3.7-rc6/0006-of-dma-fix-typos-in-generic-dma-binding-definition.patch new file mode 100644 index 0000000..a92573f --- /dev/null +++ b/patches/linux-3.7-rc6/0006-of-dma-fix-typos-in-generic-dma-binding-definition.patch @@ -0,0 +1,69 @@ +From b455947ab768efeaca48e47746206b830f13b04a Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Wed, 19 Sep 2012 10:49:48 -0400 +Subject: [PATCH] of: dma: fix typos in generic dma binding definition + +Some semicolons were left out in the examples. + +The #dma-channels and #dma-requests properties have a prefix +that is, by convention, reserved for cell size properties. +Rename those properties to dma-channels and dma-requests. + +Signed-off-by: Matt Porter <mporter@ti.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Acked-by: Jon Hunter <jon-hunter@ti.com> +Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com> +--- + Documentation/devicetree/bindings/dma/dma.txt | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/Documentation/devicetree/bindings/dma/dma.txt b/Documentation/devicetree/bindings/dma/dma.txt +index a4f59a5..8f504e6 100644 +--- a/Documentation/devicetree/bindings/dma/dma.txt ++++ b/Documentation/devicetree/bindings/dma/dma.txt +@@ -13,22 +13,22 @@ Required property: + more details. + + Optional properties: +-- #dma-channels: Number of DMA channels supported by the controller. +-- #dma-requests: Number of DMA requests signals supported by the ++- dma-channels: Number of DMA channels supported by the controller. ++- dma-requests: Number of DMA requests signals supported by the + controller. + + Example: + + dma: dma@48000000 { +- compatible = "ti,omap-sdma" ++ compatible = "ti,omap-sdma"; + reg = <0x48000000 0x1000>; + interrupts = <0 12 0x4 + 0 13 0x4 + 0 14 0x4 + 0 15 0x4>; + #dma-cells = <1>; +- #dma-channels = <32>; +- #dma-requests = <127>; ++ dma-channels = <32>; ++ dma-requests = <127>; + }; + + +@@ -61,7 +61,7 @@ Examples: + ... + dmas = <&dma 2 /* read channel */ + &dma 3>; /* write channel */ +- dma-names = "rx", "tx" ++ dma-names = "rx", "tx"; + ... + }; + +@@ -70,7 +70,7 @@ Examples: + dmas = <&dma1 5 + &dma2 7 + &dma3 2>; +- dma-names = "rx-tx", "rx-tx", "rx-tx" ++ dma-names = "rx-tx", "rx-tx", "rx-tx"; + + 3. A device with three channels, one of which has two alternatives: + diff --git a/patches/linux-3.7-rc6/0007-dmaengine-fix-build-failure-due-to-missing-semi-colo.patch b/patches/linux-3.7-rc6/0007-dmaengine-fix-build-failure-due-to-missing-semi-colo.patch new file mode 100644 index 0000000..e49b823 --- /dev/null +++ b/patches/linux-3.7-rc6/0007-dmaengine-fix-build-failure-due-to-missing-semi-colo.patch @@ -0,0 +1,24 @@ +From ae2d9b7b36e62046f28b0b9092e68fcc1f84a96a Mon Sep 17 00:00:00 2001 +From: Vinod Koul <vinod.koul@linux.intel.com> +Date: Tue, 25 Sep 2012 16:18:55 +0530 +Subject: [PATCH] dmaengine: fix build failure due to missing semi-colon + +Reported-by: Fengguang Wu <fengguang.wu@intel.com> +Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com> +--- + include/linux/dmaengine.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h +index 8cd0e25..c88f302 100644 +--- a/include/linux/dmaengine.h ++++ b/include/linux/dmaengine.h +@@ -992,7 +992,7 @@ static inline struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, + static inline struct dma_chan *dma_request_slave_channel(struct device *dev, + char *name) + { +- return NULL ++ return NULL; + } + static inline void dma_release_channel(struct dma_chan *chan) + { diff --git a/patches/linux-3.7-rc6/0008-dmaengine-edma-fix-slave-config-dependency-on-direct.patch b/patches/linux-3.7-rc6/0008-dmaengine-edma-fix-slave-config-dependency-on-direct.patch new file mode 100644 index 0000000..41e012f --- /dev/null +++ b/patches/linux-3.7-rc6/0008-dmaengine-edma-fix-slave-config-dependency-on-direct.patch @@ -0,0 +1,144 @@ +From 10e28276286e519e3be5d9ffb783bf77d48fc3ed Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Tue, 18 Sep 2012 18:57:15 +0000 +Subject: [PATCH] dmaengine: edma: fix slave config dependency on direction + +The edma_slave_config() implementation depends on the +direction field such that it will not properly configure +a slave channel when called without direction set. + +This fixes the implementation so that the slave config +is copied as is and prep_slave_sg() handles the +direction dependent handling. spi-omap2-mcspi and +omap_hsmmc both expose this bug as they configure the +slave channel config from a common path with an unconfigured +direction field. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + drivers/dma/edma.c | 55 ++++++++++++++++++++++++++-------------------------- + 1 file changed, 27 insertions(+), 28 deletions(-) + +diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c +index 05aea3c..fdcf079 100644 +--- a/drivers/dma/edma.c ++++ b/drivers/dma/edma.c +@@ -69,9 +69,7 @@ struct edma_chan { + int ch_num; + bool alloced; + int slot[EDMA_MAX_SLOTS]; +- dma_addr_t addr; +- int addr_width; +- int maxburst; ++ struct dma_slave_config cfg; + }; + + struct edma_cc { +@@ -178,29 +176,14 @@ static int edma_terminate_all(struct edma_chan *echan) + return 0; + } + +- + static int edma_slave_config(struct edma_chan *echan, +- struct dma_slave_config *config) ++ struct dma_slave_config *cfg) + { +- if ((config->src_addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES) || +- (config->dst_addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES)) ++ if (cfg->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES || ++ cfg->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) + return -EINVAL; + +- if (config->direction == DMA_MEM_TO_DEV) { +- if (config->dst_addr) +- echan->addr = config->dst_addr; +- if (config->dst_addr_width) +- echan->addr_width = config->dst_addr_width; +- if (config->dst_maxburst) +- echan->maxburst = config->dst_maxburst; +- } else if (config->direction == DMA_DEV_TO_MEM) { +- if (config->src_addr) +- echan->addr = config->src_addr; +- if (config->src_addr_width) +- echan->addr_width = config->src_addr_width; +- if (config->src_maxburst) +- echan->maxburst = config->src_maxburst; +- } ++ memcpy(&echan->cfg, cfg, sizeof(echan->cfg)); + + return 0; + } +@@ -235,6 +218,9 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( + struct edma_chan *echan = to_edma_chan(chan); + struct device *dev = chan->device->dev; + struct edma_desc *edesc; ++ dma_addr_t dev_addr; ++ enum dma_slave_buswidth dev_width; ++ u32 burst; + struct scatterlist *sg; + int i; + int acnt, bcnt, ccnt, src, dst, cidx; +@@ -243,7 +229,20 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( + if (unlikely(!echan || !sgl || !sg_len)) + return NULL; + +- if (echan->addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) { ++ if (direction == DMA_DEV_TO_MEM) { ++ dev_addr = echan->cfg.src_addr; ++ dev_width = echan->cfg.src_addr_width; ++ burst = echan->cfg.src_maxburst; ++ } else if (direction == DMA_MEM_TO_DEV) { ++ dev_addr = echan->cfg.dst_addr; ++ dev_width = echan->cfg.dst_addr_width; ++ burst = echan->cfg.dst_maxburst; ++ } else { ++ dev_err(dev, "%s: bad direction?\n", __func__); ++ return NULL; ++ } ++ ++ if (dev_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) { + dev_err(dev, "Undefined slave buswidth\n"); + return NULL; + } +@@ -275,14 +274,14 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( + } + } + +- acnt = echan->addr_width; ++ acnt = dev_width; + + /* + * If the maxburst is equal to the fifo width, use + * A-synced transfers. This allows for large contiguous + * buffer transfers using only one PaRAM set. + */ +- if (echan->maxburst == 1) { ++ if (burst == 1) { + edesc->absync = false; + ccnt = sg_dma_len(sg) / acnt / (SZ_64K - 1); + bcnt = sg_dma_len(sg) / acnt - ccnt * (SZ_64K - 1); +@@ -302,7 +301,7 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( + */ + } else { + edesc->absync = true; +- bcnt = echan->maxburst; ++ bcnt = burst; + ccnt = sg_dma_len(sg) / (acnt * bcnt); + if (ccnt > (SZ_64K - 1)) { + dev_err(dev, "Exceeded max SG segment size\n"); +@@ -313,13 +312,13 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( + + if (direction == DMA_MEM_TO_DEV) { + src = sg_dma_address(sg); +- dst = echan->addr; ++ dst = dev_addr; + src_bidx = acnt; + src_cidx = cidx; + dst_bidx = 0; + dst_cidx = 0; + } else { +- src = echan->addr; ++ src = dev_addr; + dst = sg_dma_address(sg); + src_bidx = 0; + src_cidx = 0; diff --git a/patches/linux-3.7-rc6/0009-ARM-davinci-move-private-EDMA-API-to-arm-common.patch b/patches/linux-3.7-rc6/0009-ARM-davinci-move-private-EDMA-API-to-arm-common.patch new file mode 100644 index 0000000..f766eb2 --- /dev/null +++ b/patches/linux-3.7-rc6/0009-ARM-davinci-move-private-EDMA-API-to-arm-common.patch @@ -0,0 +1,4048 @@ +From 11d28a7c4cf53a9d5eff3d01ff5f7a2436d29790 Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Wed, 22 Aug 2012 09:24:24 -0400 +Subject: [PATCH] ARM: davinci: move private EDMA API to arm/common + +Move mach-davinci/dma.c to common/edma.c so it can be used +by OMAP (specifically AM33xx) as well. This just moves the +private EDMA API but does not support OMAP. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + arch/arm/Kconfig | 1 + + arch/arm/common/Kconfig | 3 + + arch/arm/common/Makefile | 1 + + arch/arm/common/edma.c | 1588 +++++++++++++++++++++++++++ + arch/arm/mach-davinci/Makefile | 2 +- + arch/arm/mach-davinci/board-tnetv107x-evm.c | 2 +- + arch/arm/mach-davinci/davinci.h | 2 +- + arch/arm/mach-davinci/devices-tnetv107x.c | 2 +- + arch/arm/mach-davinci/devices.c | 7 +- + arch/arm/mach-davinci/dm355.c | 2 +- + arch/arm/mach-davinci/dm365.c | 2 +- + arch/arm/mach-davinci/dm644x.c | 2 +- + arch/arm/mach-davinci/dm646x.c | 2 +- + arch/arm/mach-davinci/dma.c | 1588 --------------------------- + arch/arm/mach-davinci/include/mach/da8xx.h | 2 +- + arch/arm/mach-davinci/include/mach/edma.h | 267 ----- + arch/arm/plat-omap/Kconfig | 1 + + drivers/dma/edma.c | 2 +- + drivers/mmc/host/davinci_mmc.c | 1 + + include/linux/mfd/davinci_voicecodec.h | 3 +- + include/linux/platform_data/edma.h | 198 ++++ + include/linux/platform_data/spi-davinci.h | 2 +- + sound/soc/davinci/davinci-evm.c | 1 + + sound/soc/davinci/davinci-pcm.c | 1 + + sound/soc/davinci/davinci-pcm.h | 2 +- + sound/soc/davinci/davinci-sffsdr.c | 6 +- + 26 files changed, 1815 insertions(+), 1875 deletions(-) + create mode 100644 arch/arm/common/edma.c + delete mode 100644 arch/arm/mach-davinci/dma.c + delete mode 100644 arch/arm/mach-davinci/include/mach/edma.h + create mode 100644 include/linux/platform_data/edma.h + +diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig +index ade7e92..6737b69 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -924,6 +924,7 @@ config ARCH_DAVINCI + select GENERIC_IRQ_CHIP + select HAVE_IDE + select NEED_MACH_GPIO_H ++ select TI_PRIV_EDMA + select ZONE_DMA + help + Support for TI's DaVinci platform. +diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig +index 45ceeb0..9e32d0d 100644 +--- a/arch/arm/common/Kconfig ++++ b/arch/arm/common/Kconfig +@@ -40,3 +40,6 @@ config SHARP_PARAM + + config SHARP_SCOOP + bool ++ ++config TI_PRIV_EDMA ++ bool +diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile +index e8a4e58..d09a39b 100644 +--- a/arch/arm/common/Makefile ++++ b/arch/arm/common/Makefile +@@ -13,3 +13,4 @@ obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o + obj-$(CONFIG_SHARP_SCOOP) += scoop.o + obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o + obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o ++obj-$(CONFIG_TI_PRIV_EDMA) += edma.o +diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c +new file mode 100644 +index 0000000..4411087 +--- /dev/null ++++ b/arch/arm/common/edma.c +@@ -0,0 +1,1588 @@ ++/* ++ * EDMA3 support for DaVinci ++ * ++ * Copyright (C) 2006-2009 Texas Instruments. ++ * ++ * 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 <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/slab.h> ++ ++#include <linux/platform_data/edma.h> ++ ++/* Offsets matching "struct edmacc_param" */ ++#define PARM_OPT 0x00 ++#define PARM_SRC 0x04 ++#define PARM_A_B_CNT 0x08 ++#define PARM_DST 0x0c ++#define PARM_SRC_DST_BIDX 0x10 ++#define PARM_LINK_BCNTRLD 0x14 ++#define PARM_SRC_DST_CIDX 0x18 ++#define PARM_CCNT 0x1c ++ ++#define PARM_SIZE 0x20 ++ ++/* Offsets for EDMA CC global channel registers and their shadows */ ++#define SH_ER 0x00 /* 64 bits */ ++#define SH_ECR 0x08 /* 64 bits */ ++#define SH_ESR 0x10 /* 64 bits */ ++#define SH_CER 0x18 /* 64 bits */ ++#define SH_EER 0x20 /* 64 bits */ ++#define SH_EECR 0x28 /* 64 bits */ ++#define SH_EESR 0x30 /* 64 bits */ ++#define SH_SER 0x38 /* 64 bits */ ++#define SH_SECR 0x40 /* 64 bits */ ++#define SH_IER 0x50 /* 64 bits */ ++#define SH_IECR 0x58 /* 64 bits */ ++#define SH_IESR 0x60 /* 64 bits */ ++#define SH_IPR 0x68 /* 64 bits */ ++#define SH_ICR 0x70 /* 64 bits */ ++#define SH_IEVAL 0x78 ++#define SH_QER 0x80 ++#define SH_QEER 0x84 ++#define SH_QEECR 0x88 ++#define SH_QEESR 0x8c ++#define SH_QSER 0x90 ++#define SH_QSECR 0x94 ++#define SH_SIZE 0x200 ++ ++/* Offsets for EDMA CC global registers */ ++#define EDMA_REV 0x0000 ++#define EDMA_CCCFG 0x0004 ++#define EDMA_QCHMAP 0x0200 /* 8 registers */ ++#define EDMA_DMAQNUM 0x0240 /* 8 registers (4 on OMAP-L1xx) */ ++#define EDMA_QDMAQNUM 0x0260 ++#define EDMA_QUETCMAP 0x0280 ++#define EDMA_QUEPRI 0x0284 ++#define EDMA_EMR 0x0300 /* 64 bits */ ++#define EDMA_EMCR 0x0308 /* 64 bits */ ++#define EDMA_QEMR 0x0310 ++#define EDMA_QEMCR 0x0314 ++#define EDMA_CCERR 0x0318 ++#define EDMA_CCERRCLR 0x031c ++#define EDMA_EEVAL 0x0320 ++#define EDMA_DRAE 0x0340 /* 4 x 64 bits*/ ++#define EDMA_QRAE 0x0380 /* 4 registers */ ++#define EDMA_QUEEVTENTRY 0x0400 /* 2 x 16 registers */ ++#define EDMA_QSTAT 0x0600 /* 2 registers */ ++#define EDMA_QWMTHRA 0x0620 ++#define EDMA_QWMTHRB 0x0624 ++#define EDMA_CCSTAT 0x0640 ++ ++#define EDMA_M 0x1000 /* global channel registers */ ++#define EDMA_ECR 0x1008 ++#define EDMA_ECRH 0x100C ++#define EDMA_SHADOW0 0x2000 /* 4 regions shadowing global channels */ ++#define EDMA_PARM 0x4000 /* 128 param entries */ ++ ++#define PARM_OFFSET(param_no) (EDMA_PARM + ((param_no) << 5)) ++ ++#define EDMA_DCHMAP 0x0100 /* 64 registers */ ++#define CHMAP_EXIST BIT(24) ++ ++#define EDMA_MAX_DMACH 64 ++#define EDMA_MAX_PARAMENTRY 512 ++ ++/*****************************************************************************/ ++ ++static void __iomem *edmacc_regs_base[EDMA_MAX_CC]; ++ ++static inline unsigned int edma_read(unsigned ctlr, int offset) ++{ ++ return (unsigned int)__raw_readl(edmacc_regs_base[ctlr] + offset); ++} ++ ++static inline void edma_write(unsigned ctlr, int offset, int val) ++{ ++ __raw_writel(val, edmacc_regs_base[ctlr] + offset); ++} ++static inline void edma_modify(unsigned ctlr, int offset, unsigned and, ++ unsigned or) ++{ ++ unsigned val = edma_read(ctlr, offset); ++ val &= and; ++ val |= or; ++ edma_write(ctlr, offset, val); ++} ++static inline void edma_and(unsigned ctlr, int offset, unsigned and) ++{ ++ unsigned val = edma_read(ctlr, offset); ++ val &= and; ++ edma_write(ctlr, offset, val); ++} ++static inline void edma_or(unsigned ctlr, int offset, unsigned or) ++{ ++ unsigned val = edma_read(ctlr, offset); ++ val |= or; ++ edma_write(ctlr, offset, val); ++} ++static inline unsigned int edma_read_array(unsigned ctlr, int offset, int i) ++{ ++ return edma_read(ctlr, offset + (i << 2)); ++} ++static inline void edma_write_array(unsigned ctlr, int offset, int i, ++ unsigned val) ++{ ++ edma_write(ctlr, offset + (i << 2), val); ++} ++static inline void edma_modify_array(unsigned ctlr, int offset, int i, ++ unsigned and, unsigned or) ++{ ++ edma_modify(ctlr, offset + (i << 2), and, or); ++} ++static inline void edma_or_array(unsigned ctlr, int offset, int i, unsigned or) ++{ ++ edma_or(ctlr, offset + (i << 2), or); ++} ++static inline void edma_or_array2(unsigned ctlr, int offset, int i, int j, ++ unsigned or) ++{ ++ edma_or(ctlr, offset + ((i*2 + j) << 2), or); ++} ++static inline void edma_write_array2(unsigned ctlr, int offset, int i, int j, ++ unsigned val) ++{ ++ edma_write(ctlr, offset + ((i*2 + j) << 2), val); ++} ++static inline unsigned int edma_shadow0_read(unsigned ctlr, int offset) ++{ ++ return edma_read(ctlr, EDMA_SHADOW0 + offset); ++} ++static inline unsigned int edma_shadow0_read_array(unsigned ctlr, int offset, ++ int i) ++{ ++ return edma_read(ctlr, EDMA_SHADOW0 + offset + (i << 2)); ++} ++static inline void edma_shadow0_write(unsigned ctlr, int offset, unsigned val) ++{ ++ edma_write(ctlr, EDMA_SHADOW0 + offset, val); ++} ++static inline void edma_shadow0_write_array(unsigned ctlr, int offset, int i, ++ unsigned val) ++{ ++ edma_write(ctlr, EDMA_SHADOW0 + offset + (i << 2), val); ++} ++static inline unsigned int edma_parm_read(unsigned ctlr, int offset, ++ int param_no) ++{ ++ return edma_read(ctlr, EDMA_PARM + offset + (param_no << 5)); ++} ++static inline void edma_parm_write(unsigned ctlr, int offset, int param_no, ++ unsigned val) ++{ ++ edma_write(ctlr, EDMA_PARM + offset + (param_no << 5), val); ++} ++static inline void edma_parm_modify(unsigned ctlr, int offset, int param_no, ++ unsigned and, unsigned or) ++{ ++ edma_modify(ctlr, EDMA_PARM + offset + (param_no << 5), and, or); ++} ++static inline void edma_parm_and(unsigned ctlr, int offset, int param_no, ++ unsigned and) ++{ ++ edma_and(ctlr, EDMA_PARM + offset + (param_no << 5), and); ++} ++static inline void edma_parm_or(unsigned ctlr, int offset, int param_no, ++ unsigned or) ++{ ++ edma_or(ctlr, EDMA_PARM + offset + (param_no << 5), or); ++} ++ ++static inline void set_bits(int offset, int len, unsigned long *p) ++{ ++ for (; len > 0; len--) ++ set_bit(offset + (len - 1), p); ++} ++ ++static inline void clear_bits(int offset, int len, unsigned long *p) ++{ ++ for (; len > 0; len--) ++ clear_bit(offset + (len - 1), p); ++} ++ ++/*****************************************************************************/ ++ ++/* actual number of DMA channels and slots on this silicon */ ++struct edma { ++ /* how many dma resources of each type */ ++ unsigned num_channels; ++ unsigned num_region; ++ unsigned num_slots; ++ unsigned num_tc; ++ unsigned num_cc; ++ enum dma_event_q default_queue; ++ ++ /* list of channels with no even trigger; terminated by "-1" */ ++ const s8 *noevent; ++ ++ /* The edma_inuse bit for each PaRAM slot is clear unless the ++ * channel is in use ... by ARM or DSP, for QDMA, or whatever. ++ */ ++ DECLARE_BITMAP(edma_inuse, EDMA_MAX_PARAMENTRY); ++ ++ /* The edma_unused bit for each channel is clear unless ++ * it is not being used on this platform. It uses a bit ++ * of SOC-specific initialization code. ++ */ ++ DECLARE_BITMAP(edma_unused, EDMA_MAX_DMACH); ++ ++ unsigned irq_res_start; ++ unsigned irq_res_end; ++ ++ struct dma_interrupt_data { ++ void (*callback)(unsigned channel, unsigned short ch_status, ++ void *data); ++ void *data; ++ } intr_data[EDMA_MAX_DMACH]; ++}; ++ ++static struct edma *edma_cc[EDMA_MAX_CC]; ++static int arch_num_cc; ++ ++/* dummy param set used to (re)initialize parameter RAM slots */ ++static const struct edmacc_param dummy_paramset = { ++ .link_bcntrld = 0xffff, ++ .ccnt = 1, ++}; ++ ++/*****************************************************************************/ ++ ++static void map_dmach_queue(unsigned ctlr, unsigned ch_no, ++ enum dma_event_q queue_no) ++{ ++ int bit = (ch_no & 0x7) * 4; ++ ++ /* default to low priority queue */ ++ if (queue_no == EVENTQ_DEFAULT) ++ queue_no = edma_cc[ctlr]->default_queue; ++ ++ queue_no &= 7; ++ edma_modify_array(ctlr, EDMA_DMAQNUM, (ch_no >> 3), ++ ~(0x7 << bit), queue_no << bit); ++} ++ ++static void __init map_queue_tc(unsigned ctlr, int queue_no, int tc_no) ++{ ++ int bit = queue_no * 4; ++ edma_modify(ctlr, EDMA_QUETCMAP, ~(0x7 << bit), ((tc_no & 0x7) << bit)); ++} ++ ++static void __init assign_priority_to_queue(unsigned ctlr, int queue_no, ++ int priority) ++{ ++ int bit = queue_no * 4; ++ edma_modify(ctlr, EDMA_QUEPRI, ~(0x7 << bit), ++ ((priority & 0x7) << bit)); ++} ++ ++/** ++ * map_dmach_param - Maps channel number to param entry number ++ * ++ * This maps the dma channel number to param entry numberter. In ++ * other words using the DMA channel mapping registers a param entry ++ * can be mapped to any channel ++ * ++ * Callers are responsible for ensuring the channel mapping logic is ++ * included in that particular EDMA variant (Eg : dm646x) ++ * ++ */ ++static void __init map_dmach_param(unsigned ctlr) ++{ ++ int i; ++ for (i = 0; i < EDMA_MAX_DMACH; i++) ++ edma_write_array(ctlr, EDMA_DCHMAP , i , (i << 5)); ++} ++ ++static inline void ++setup_dma_interrupt(unsigned lch, ++ void (*callback)(unsigned channel, u16 ch_status, void *data), ++ void *data) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(lch); ++ lch = EDMA_CHAN_SLOT(lch); ++ ++ if (!callback) ++ edma_shadow0_write_array(ctlr, SH_IECR, lch >> 5, ++ BIT(lch & 0x1f)); ++ ++ edma_cc[ctlr]->intr_data[lch].callback = callback; ++ edma_cc[ctlr]->intr_data[lch].data = data; ++ ++ if (callback) { ++ edma_shadow0_write_array(ctlr, SH_ICR, lch >> 5, ++ BIT(lch & 0x1f)); ++ edma_shadow0_write_array(ctlr, SH_IESR, lch >> 5, ++ BIT(lch & 0x1f)); ++ } ++} ++ ++static int irq2ctlr(int irq) ++{ ++ if (irq >= edma_cc[0]->irq_res_start && irq <= edma_cc[0]->irq_res_end) ++ return 0; ++ else if (irq >= edma_cc[1]->irq_res_start && ++ irq <= edma_cc[1]->irq_res_end) ++ return 1; ++ ++ return -1; ++} ++ ++/****************************************************************************** ++ * ++ * DMA interrupt handler ++ * ++ *****************************************************************************/ ++static irqreturn_t dma_irq_handler(int irq, void *data) ++{ ++ int ctlr; ++ u32 sh_ier; ++ u32 sh_ipr; ++ u32 bank; ++ ++ ctlr = irq2ctlr(irq); ++ if (ctlr < 0) ++ return IRQ_NONE; ++ ++ dev_dbg(data, "dma_irq_handler\n"); ++ ++ sh_ipr = edma_shadow0_read_array(ctlr, SH_IPR, 0); ++ if (!sh_ipr) { ++ sh_ipr = edma_shadow0_read_array(ctlr, SH_IPR, 1); ++ if (!sh_ipr) ++ return IRQ_NONE; ++ sh_ier = edma_shadow0_read_array(ctlr, SH_IER, 1); ++ bank = 1; ++ } else { ++ sh_ier = edma_shadow0_read_array(ctlr, SH_IER, 0); ++ bank = 0; ++ } ++ ++ do { ++ u32 slot; ++ u32 channel; ++ ++ dev_dbg(data, "IPR%d %08x\n", bank, sh_ipr); ++ ++ slot = __ffs(sh_ipr); ++ sh_ipr &= ~(BIT(slot)); ++ ++ if (sh_ier & BIT(slot)) { ++ channel = (bank << 5) | slot; ++ /* Clear the corresponding IPR bits */ ++ edma_shadow0_write_array(ctlr, SH_ICR, bank, ++ BIT(slot)); ++ if (edma_cc[ctlr]->intr_data[channel].callback) ++ edma_cc[ctlr]->intr_data[channel].callback( ++ channel, DMA_COMPLETE, ++ edma_cc[ctlr]->intr_data[channel].data); ++ } ++ } while (sh_ipr); ++ ++ edma_shadow0_write(ctlr, SH_IEVAL, 1); ++ return IRQ_HANDLED; ++} ++ ++/****************************************************************************** ++ * ++ * DMA error interrupt handler ++ * ++ *****************************************************************************/ ++static irqreturn_t dma_ccerr_handler(int irq, void *data) ++{ ++ int i; ++ int ctlr; ++ unsigned int cnt = 0; ++ ++ ctlr = irq2ctlr(irq); ++ if (ctlr < 0) ++ return IRQ_NONE; ++ ++ dev_dbg(data, "dma_ccerr_handler\n"); ++ ++ if ((edma_read_array(ctlr, EDMA_EMR, 0) == 0) && ++ (edma_read_array(ctlr, EDMA_EMR, 1) == 0) && ++ (edma_read(ctlr, EDMA_QEMR) == 0) && ++ (edma_read(ctlr, EDMA_CCERR) == 0)) ++ return IRQ_NONE; ++ ++ while (1) { ++ int j = -1; ++ if (edma_read_array(ctlr, EDMA_EMR, 0)) ++ j = 0; ++ else if (edma_read_array(ctlr, EDMA_EMR, 1)) ++ j = 1; ++ if (j >= 0) { ++ dev_dbg(data, "EMR%d %08x\n", j, ++ edma_read_array(ctlr, EDMA_EMR, j)); ++ for (i = 0; i < 32; i++) { ++ int k = (j << 5) + i; ++ if (edma_read_array(ctlr, EDMA_EMR, j) & ++ BIT(i)) { ++ /* Clear the corresponding EMR bits */ ++ edma_write_array(ctlr, EDMA_EMCR, j, ++ BIT(i)); ++ /* Clear any SER */ ++ edma_shadow0_write_array(ctlr, SH_SECR, ++ j, BIT(i)); ++ if (edma_cc[ctlr]->intr_data[k]. ++ callback) { ++ edma_cc[ctlr]->intr_data[k]. ++ callback(k, ++ DMA_CC_ERROR, ++ edma_cc[ctlr]->intr_data ++ [k].data); ++ } ++ } ++ } ++ } else if (edma_read(ctlr, EDMA_QEMR)) { ++ dev_dbg(data, "QEMR %02x\n", ++ edma_read(ctlr, EDMA_QEMR)); ++ for (i = 0; i < 8; i++) { ++ if (edma_read(ctlr, EDMA_QEMR) & BIT(i)) { ++ /* Clear the corresponding IPR bits */ ++ edma_write(ctlr, EDMA_QEMCR, BIT(i)); ++ edma_shadow0_write(ctlr, SH_QSECR, ++ BIT(i)); ++ ++ /* NOTE: not reported!! */ ++ } ++ } ++ } else if (edma_read(ctlr, EDMA_CCERR)) { ++ dev_dbg(data, "CCERR %08x\n", ++ edma_read(ctlr, EDMA_CCERR)); ++ /* FIXME: CCERR.BIT(16) ignored! much better ++ * to just write CCERRCLR with CCERR value... ++ */ ++ for (i = 0; i < 8; i++) { ++ if (edma_read(ctlr, EDMA_CCERR) & BIT(i)) { ++ /* Clear the corresponding IPR bits */ ++ edma_write(ctlr, EDMA_CCERRCLR, BIT(i)); ++ ++ /* NOTE: not reported!! */ ++ } ++ } ++ } ++ if ((edma_read_array(ctlr, EDMA_EMR, 0) == 0) && ++ (edma_read_array(ctlr, EDMA_EMR, 1) == 0) && ++ (edma_read(ctlr, EDMA_QEMR) == 0) && ++ (edma_read(ctlr, EDMA_CCERR) == 0)) ++ break; ++ cnt++; ++ if (cnt > 10) ++ break; ++ } ++ edma_write(ctlr, EDMA_EEVAL, 1); ++ return IRQ_HANDLED; ++} ++ ++/****************************************************************************** ++ * ++ * Transfer controller error interrupt handlers ++ * ++ *****************************************************************************/ ++ ++#define tc_errs_handled false /* disabled as long as they're NOPs */ ++ ++static irqreturn_t dma_tc0err_handler(int irq, void *data) ++{ ++ dev_dbg(data, "dma_tc0err_handler\n"); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t dma_tc1err_handler(int irq, void *data) ++{ ++ dev_dbg(data, "dma_tc1err_handler\n"); ++ return IRQ_HANDLED; ++} ++ ++static int reserve_contiguous_slots(int ctlr, unsigned int id, ++ unsigned int num_slots, ++ unsigned int start_slot) ++{ ++ int i, j; ++ unsigned int count = num_slots; ++ int stop_slot = start_slot; ++ DECLARE_BITMAP(tmp_inuse, EDMA_MAX_PARAMENTRY); ++ ++ for (i = start_slot; i < edma_cc[ctlr]->num_slots; ++i) { ++ j = EDMA_CHAN_SLOT(i); ++ if (!test_and_set_bit(j, edma_cc[ctlr]->edma_inuse)) { ++ /* Record our current beginning slot */ ++ if (count == num_slots) ++ stop_slot = i; ++ ++ count--; ++ set_bit(j, tmp_inuse); ++ ++ if (count == 0) ++ break; ++ } else { ++ clear_bit(j, tmp_inuse); ++ ++ if (id == EDMA_CONT_PARAMS_FIXED_EXACT) { ++ stop_slot = i; ++ break; ++ } else { ++ count = num_slots; ++ } ++ } ++ } ++ ++ /* ++ * We have to clear any bits that we set ++ * if we run out parameter RAM slots, i.e we do find a set ++ * of contiguous parameter RAM slots but do not find the exact number ++ * requested as we may reach the total number of parameter RAM slots ++ */ ++ if (i == edma_cc[ctlr]->num_slots) ++ stop_slot = i; ++ ++ j = start_slot; ++ for_each_set_bit_from(j, tmp_inuse, stop_slot) ++ clear_bit(j, edma_cc[ctlr]->edma_inuse); ++ ++ if (count) ++ return -EBUSY; ++ ++ for (j = i - num_slots + 1; j <= i; ++j) ++ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(j), ++ &dummy_paramset, PARM_SIZE); ++ ++ return EDMA_CTLR_CHAN(ctlr, i - num_slots + 1); ++} ++ ++static int prepare_unused_channel_list(struct device *dev, void *data) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ int i, ctlr; ++ ++ for (i = 0; i < pdev->num_resources; i++) { ++ if ((pdev->resource[i].flags & IORESOURCE_DMA) && ++ (int)pdev->resource[i].start >= 0) { ++ ctlr = EDMA_CTLR(pdev->resource[i].start); ++ clear_bit(EDMA_CHAN_SLOT(pdev->resource[i].start), ++ edma_cc[ctlr]->edma_unused); ++ } ++ } ++ ++ return 0; ++} ++ ++/*-----------------------------------------------------------------------*/ ++ ++static bool unused_chan_list_done; ++ ++/* Resource alloc/free: dma channels, parameter RAM slots */ ++ ++/** ++ * edma_alloc_channel - allocate DMA channel and paired parameter RAM ++ * @channel: specific channel to allocate; negative for "any unmapped channel" ++ * @callback: optional; to be issued on DMA completion or errors ++ * @data: passed to callback ++ * @eventq_no: an EVENTQ_* constant, used to choose which Transfer ++ * Controller (TC) executes requests using this channel. Use ++ * EVENTQ_DEFAULT unless you really need a high priority queue. ++ * ++ * This allocates a DMA channel and its associated parameter RAM slot. ++ * The parameter RAM is initialized to hold a dummy transfer. ++ * ++ * Normal use is to pass a specific channel number as @channel, to make ++ * use of hardware events mapped to that channel. When the channel will ++ * be used only for software triggering or event chaining, channels not ++ * mapped to hardware events (or mapped to unused events) are preferable. ++ * ++ * DMA transfers start from a channel using edma_start(), or by ++ * chaining. When the transfer described in that channel's parameter RAM ++ * slot completes, that slot's data may be reloaded through a link. ++ * ++ * DMA errors are only reported to the @callback associated with the ++ * channel driving that transfer, but transfer completion callbacks can ++ * be sent to another channel under control of the TCC field in ++ * the option word of the transfer's parameter RAM set. Drivers must not ++ * use DMA transfer completion callbacks for channels they did not allocate. ++ * (The same applies to TCC codes used in transfer chaining.) ++ * ++ * Returns the number of the channel, else negative errno. ++ */ ++int edma_alloc_channel(int channel, ++ void (*callback)(unsigned channel, u16 ch_status, void *data), ++ void *data, ++ enum dma_event_q eventq_no) ++{ ++ unsigned i, done = 0, ctlr = 0; ++ int ret = 0; ++ ++ if (!unused_chan_list_done) { ++ /* ++ * Scan all the platform devices to find out the EDMA channels ++ * used and clear them in the unused list, making the rest ++ * available for ARM usage. ++ */ ++ ret = bus_for_each_dev(&platform_bus_type, NULL, NULL, ++ prepare_unused_channel_list); ++ if (ret < 0) ++ return ret; ++ ++ unused_chan_list_done = true; ++ } ++ ++ if (channel >= 0) { ++ ctlr = EDMA_CTLR(channel); ++ channel = EDMA_CHAN_SLOT(channel); ++ } ++ ++ if (channel < 0) { ++ for (i = 0; i < arch_num_cc; i++) { ++ channel = 0; ++ for (;;) { ++ channel = find_next_bit(edma_cc[i]->edma_unused, ++ edma_cc[i]->num_channels, ++ channel); ++ if (channel == edma_cc[i]->num_channels) ++ break; ++ if (!test_and_set_bit(channel, ++ edma_cc[i]->edma_inuse)) { ++ done = 1; ++ ctlr = i; ++ break; ++ } ++ channel++; ++ } ++ if (done) ++ break; ++ } ++ if (!done) ++ return -ENOMEM; ++ } else if (channel >= edma_cc[ctlr]->num_channels) { ++ return -EINVAL; ++ } else if (test_and_set_bit(channel, edma_cc[ctlr]->edma_inuse)) { ++ return -EBUSY; ++ } ++ ++ /* ensure access through shadow region 0 */ ++ edma_or_array2(ctlr, EDMA_DRAE, 0, channel >> 5, BIT(channel & 0x1f)); ++ ++ /* ensure no events are pending */ ++ edma_stop(EDMA_CTLR_CHAN(ctlr, channel)); ++ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(channel), ++ &dummy_paramset, PARM_SIZE); ++ ++ if (callback) ++ setup_dma_interrupt(EDMA_CTLR_CHAN(ctlr, channel), ++ callback, data); ++ ++ map_dmach_queue(ctlr, channel, eventq_no); ++ ++ return EDMA_CTLR_CHAN(ctlr, channel); ++} ++EXPORT_SYMBOL(edma_alloc_channel); ++ ++ ++/** ++ * edma_free_channel - deallocate DMA channel ++ * @channel: dma channel returned from edma_alloc_channel() ++ * ++ * This deallocates the DMA channel and associated parameter RAM slot ++ * allocated by edma_alloc_channel(). ++ * ++ * Callers are responsible for ensuring the channel is inactive, and ++ * will not be reactivated by linking, chaining, or software calls to ++ * edma_start(). ++ */ ++void edma_free_channel(unsigned channel) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(channel); ++ channel = EDMA_CHAN_SLOT(channel); ++ ++ if (channel >= edma_cc[ctlr]->num_channels) ++ return; ++ ++ setup_dma_interrupt(channel, NULL, NULL); ++ /* REVISIT should probably take out of shadow region 0 */ ++ ++ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(channel), ++ &dummy_paramset, PARM_SIZE); ++ clear_bit(channel, edma_cc[ctlr]->edma_inuse); ++} ++EXPORT_SYMBOL(edma_free_channel); ++ ++/** ++ * edma_alloc_slot - allocate DMA parameter RAM ++ * @slot: specific slot to allocate; negative for "any unused slot" ++ * ++ * This allocates a parameter RAM slot, initializing it to hold a ++ * dummy transfer. Slots allocated using this routine have not been ++ * mapped to a hardware DMA channel, and will normally be used by ++ * linking to them from a slot associated with a DMA channel. ++ * ++ * Normal use is to pass EDMA_SLOT_ANY as the @slot, but specific ++ * slots may be allocated on behalf of DSP firmware. ++ * ++ * Returns the number of the slot, else negative errno. ++ */ ++int edma_alloc_slot(unsigned ctlr, int slot) ++{ ++ if (slot >= 0) ++ slot = EDMA_CHAN_SLOT(slot); ++ ++ if (slot < 0) { ++ slot = edma_cc[ctlr]->num_channels; ++ for (;;) { ++ slot = find_next_zero_bit(edma_cc[ctlr]->edma_inuse, ++ edma_cc[ctlr]->num_slots, slot); ++ if (slot == edma_cc[ctlr]->num_slots) ++ return -ENOMEM; ++ if (!test_and_set_bit(slot, edma_cc[ctlr]->edma_inuse)) ++ break; ++ } ++ } else if (slot < edma_cc[ctlr]->num_channels || ++ slot >= edma_cc[ctlr]->num_slots) { ++ return -EINVAL; ++ } else if (test_and_set_bit(slot, edma_cc[ctlr]->edma_inuse)) { ++ return -EBUSY; ++ } ++ ++ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot), ++ &dummy_paramset, PARM_SIZE); ++ ++ return EDMA_CTLR_CHAN(ctlr, slot); ++} ++EXPORT_SYMBOL(edma_alloc_slot); ++ ++/** ++ * edma_free_slot - deallocate DMA parameter RAM ++ * @slot: parameter RAM slot returned from edma_alloc_slot() ++ * ++ * This deallocates the parameter RAM slot allocated by edma_alloc_slot(). ++ * Callers are responsible for ensuring the slot is inactive, and will ++ * not be activated. ++ */ ++void edma_free_slot(unsigned slot) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(slot); ++ slot = EDMA_CHAN_SLOT(slot); ++ ++ if (slot < edma_cc[ctlr]->num_channels || ++ slot >= edma_cc[ctlr]->num_slots) ++ return; ++ ++ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot), ++ &dummy_paramset, PARM_SIZE); ++ clear_bit(slot, edma_cc[ctlr]->edma_inuse); ++} ++EXPORT_SYMBOL(edma_free_slot); ++ ++ ++/** ++ * edma_alloc_cont_slots- alloc contiguous parameter RAM slots ++ * The API will return the starting point of a set of ++ * contiguous parameter RAM slots that have been requested ++ * ++ * @id: can only be EDMA_CONT_PARAMS_ANY or EDMA_CONT_PARAMS_FIXED_EXACT ++ * or EDMA_CONT_PARAMS_FIXED_NOT_EXACT ++ * @count: number of contiguous Paramter RAM slots ++ * @slot - the start value of Parameter RAM slot that should be passed if id ++ * is EDMA_CONT_PARAMS_FIXED_EXACT or EDMA_CONT_PARAMS_FIXED_NOT_EXACT ++ * ++ * If id is EDMA_CONT_PARAMS_ANY then the API starts looking for a set of ++ * contiguous Parameter RAM slots from parameter RAM 64 in the case of ++ * DaVinci SOCs and 32 in the case of DA8xx SOCs. ++ * ++ * If id is EDMA_CONT_PARAMS_FIXED_EXACT then the API starts looking for a ++ * set of contiguous parameter RAM slots from the "slot" that is passed as an ++ * argument to the API. ++ * ++ * If id is EDMA_CONT_PARAMS_FIXED_NOT_EXACT then the API initially tries ++ * starts looking for a set of contiguous parameter RAMs from the "slot" ++ * that is passed as an argument to the API. On failure the API will try to ++ * find a set of contiguous Parameter RAM slots from the remaining Parameter ++ * RAM slots ++ */ ++int edma_alloc_cont_slots(unsigned ctlr, unsigned int id, int slot, int count) ++{ ++ /* ++ * The start slot requested should be greater than ++ * the number of channels and lesser than the total number ++ * of slots ++ */ ++ if ((id != EDMA_CONT_PARAMS_ANY) && ++ (slot < edma_cc[ctlr]->num_channels || ++ slot >= edma_cc[ctlr]->num_slots)) ++ return -EINVAL; ++ ++ /* ++ * The number of parameter RAM slots requested cannot be less than 1 ++ * and cannot be more than the number of slots minus the number of ++ * channels ++ */ ++ if (count < 1 || count > ++ (edma_cc[ctlr]->num_slots - edma_cc[ctlr]->num_channels)) ++ return -EINVAL; ++ ++ switch (id) { ++ case EDMA_CONT_PARAMS_ANY: ++ return reserve_contiguous_slots(ctlr, id, count, ++ edma_cc[ctlr]->num_channels); ++ case EDMA_CONT_PARAMS_FIXED_EXACT: ++ case EDMA_CONT_PARAMS_FIXED_NOT_EXACT: ++ return reserve_contiguous_slots(ctlr, id, count, slot); ++ default: ++ return -EINVAL; ++ } ++ ++} ++EXPORT_SYMBOL(edma_alloc_cont_slots); ++ ++/** ++ * edma_free_cont_slots - deallocate DMA parameter RAM slots ++ * @slot: first parameter RAM of a set of parameter RAM slots to be freed ++ * @count: the number of contiguous parameter RAM slots to be freed ++ * ++ * This deallocates the parameter RAM slots allocated by ++ * edma_alloc_cont_slots. ++ * Callers/applications need to keep track of sets of contiguous ++ * parameter RAM slots that have been allocated using the edma_alloc_cont_slots ++ * API. ++ * Callers are responsible for ensuring the slots are inactive, and will ++ * not be activated. ++ */ ++int edma_free_cont_slots(unsigned slot, int count) ++{ ++ unsigned ctlr, slot_to_free; ++ int i; ++ ++ ctlr = EDMA_CTLR(slot); ++ slot = EDMA_CHAN_SLOT(slot); ++ ++ if (slot < edma_cc[ctlr]->num_channels || ++ slot >= edma_cc[ctlr]->num_slots || ++ count < 1) ++ return -EINVAL; ++ ++ for (i = slot; i < slot + count; ++i) { ++ ctlr = EDMA_CTLR(i); ++ slot_to_free = EDMA_CHAN_SLOT(i); ++ ++ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot_to_free), ++ &dummy_paramset, PARM_SIZE); ++ clear_bit(slot_to_free, edma_cc[ctlr]->edma_inuse); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(edma_free_cont_slots); ++ ++/*-----------------------------------------------------------------------*/ ++ ++/* Parameter RAM operations (i) -- read/write partial slots */ ++ ++/** ++ * edma_set_src - set initial DMA source address in parameter RAM slot ++ * @slot: parameter RAM slot being configured ++ * @src_port: physical address of source (memory, controller FIFO, etc) ++ * @addressMode: INCR, except in very rare cases ++ * @fifoWidth: ignored unless @addressMode is FIFO, else specifies the ++ * width to use when addressing the fifo (e.g. W8BIT, W32BIT) ++ * ++ * Note that the source address is modified during the DMA transfer ++ * according to edma_set_src_index(). ++ */ ++void edma_set_src(unsigned slot, dma_addr_t src_port, ++ enum address_mode mode, enum fifo_width width) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(slot); ++ slot = EDMA_CHAN_SLOT(slot); ++ ++ if (slot < edma_cc[ctlr]->num_slots) { ++ unsigned int i = edma_parm_read(ctlr, PARM_OPT, slot); ++ ++ if (mode) { ++ /* set SAM and program FWID */ ++ i = (i & ~(EDMA_FWID)) | (SAM | ((width & 0x7) << 8)); ++ } else { ++ /* clear SAM */ ++ i &= ~SAM; ++ } ++ edma_parm_write(ctlr, PARM_OPT, slot, i); ++ ++ /* set the source port address ++ in source register of param structure */ ++ edma_parm_write(ctlr, PARM_SRC, slot, src_port); ++ } ++} ++EXPORT_SYMBOL(edma_set_src); ++ ++/** ++ * edma_set_dest - set initial DMA destination address in parameter RAM slot ++ * @slot: parameter RAM slot being configured ++ * @dest_port: physical address of destination (memory, controller FIFO, etc) ++ * @addressMode: INCR, except in very rare cases ++ * @fifoWidth: ignored unless @addressMode is FIFO, else specifies the ++ * width to use when addressing the fifo (e.g. W8BIT, W32BIT) ++ * ++ * Note that the destination address is modified during the DMA transfer ++ * according to edma_set_dest_index(). ++ */ ++void edma_set_dest(unsigned slot, dma_addr_t dest_port, ++ enum address_mode mode, enum fifo_width width) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(slot); ++ slot = EDMA_CHAN_SLOT(slot); ++ ++ if (slot < edma_cc[ctlr]->num_slots) { ++ unsigned int i = edma_parm_read(ctlr, PARM_OPT, slot); ++ ++ if (mode) { ++ /* set DAM and program FWID */ ++ i = (i & ~(EDMA_FWID)) | (DAM | ((width & 0x7) << 8)); ++ } else { ++ /* clear DAM */ ++ i &= ~DAM; ++ } ++ edma_parm_write(ctlr, PARM_OPT, slot, i); ++ /* set the destination port address ++ in dest register of param structure */ ++ edma_parm_write(ctlr, PARM_DST, slot, dest_port); ++ } ++} ++EXPORT_SYMBOL(edma_set_dest); ++ ++/** ++ * edma_get_position - returns the current transfer points ++ * @slot: parameter RAM slot being examined ++ * @src: pointer to source port position ++ * @dst: pointer to destination port position ++ * ++ * Returns current source and destination addresses for a particular ++ * parameter RAM slot. Its channel should not be active when this is called. ++ */ ++void edma_get_position(unsigned slot, dma_addr_t *src, dma_addr_t *dst) ++{ ++ struct edmacc_param temp; ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(slot); ++ slot = EDMA_CHAN_SLOT(slot); ++ ++ edma_read_slot(EDMA_CTLR_CHAN(ctlr, slot), &temp); ++ if (src != NULL) ++ *src = temp.src; ++ if (dst != NULL) ++ *dst = temp.dst; ++} ++EXPORT_SYMBOL(edma_get_position); ++ ++/** ++ * edma_set_src_index - configure DMA source address indexing ++ * @slot: parameter RAM slot being configured ++ * @src_bidx: byte offset between source arrays in a frame ++ * @src_cidx: byte offset between source frames in a block ++ * ++ * Offsets are specified to support either contiguous or discontiguous ++ * memory transfers, or repeated access to a hardware register, as needed. ++ * When accessing hardware registers, both offsets are normally zero. ++ */ ++void edma_set_src_index(unsigned slot, s16 src_bidx, s16 src_cidx) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(slot); ++ slot = EDMA_CHAN_SLOT(slot); ++ ++ if (slot < edma_cc[ctlr]->num_slots) { ++ edma_parm_modify(ctlr, PARM_SRC_DST_BIDX, slot, ++ 0xffff0000, src_bidx); ++ edma_parm_modify(ctlr, PARM_SRC_DST_CIDX, slot, ++ 0xffff0000, src_cidx); ++ } ++} ++EXPORT_SYMBOL(edma_set_src_index); ++ ++/** ++ * edma_set_dest_index - configure DMA destination address indexing ++ * @slot: parameter RAM slot being configured ++ * @dest_bidx: byte offset between destination arrays in a frame ++ * @dest_cidx: byte offset between destination frames in a block ++ * ++ * Offsets are specified to support either contiguous or discontiguous ++ * memory transfers, or repeated access to a hardware register, as needed. ++ * When accessing hardware registers, both offsets are normally zero. ++ */ ++void edma_set_dest_index(unsigned slot, s16 dest_bidx, s16 dest_cidx) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(slot); ++ slot = EDMA_CHAN_SLOT(slot); ++ ++ if (slot < edma_cc[ctlr]->num_slots) { ++ edma_parm_modify(ctlr, PARM_SRC_DST_BIDX, slot, ++ 0x0000ffff, dest_bidx << 16); ++ edma_parm_modify(ctlr, PARM_SRC_DST_CIDX, slot, ++ 0x0000ffff, dest_cidx << 16); ++ } ++} ++EXPORT_SYMBOL(edma_set_dest_index); ++ ++/** ++ * edma_set_transfer_params - configure DMA transfer parameters ++ * @slot: parameter RAM slot being configured ++ * @acnt: how many bytes per array (at least one) ++ * @bcnt: how many arrays per frame (at least one) ++ * @ccnt: how many frames per block (at least one) ++ * @bcnt_rld: used only for A-Synchronized transfers; this specifies ++ * the value to reload into bcnt when it decrements to zero ++ * @sync_mode: ASYNC or ABSYNC ++ * ++ * See the EDMA3 documentation to understand how to configure and link ++ * transfers using the fields in PaRAM slots. If you are not doing it ++ * all at once with edma_write_slot(), you will use this routine ++ * plus two calls each for source and destination, setting the initial ++ * address and saying how to index that address. ++ * ++ * An example of an A-Synchronized transfer is a serial link using a ++ * single word shift register. In that case, @acnt would be equal to ++ * that word size; the serial controller issues a DMA synchronization ++ * event to transfer each word, and memory access by the DMA transfer ++ * controller will be word-at-a-time. ++ * ++ * An example of an AB-Synchronized transfer is a device using a FIFO. ++ * In that case, @acnt equals the FIFO width and @bcnt equals its depth. ++ * The controller with the FIFO issues DMA synchronization events when ++ * the FIFO threshold is reached, and the DMA transfer controller will ++ * transfer one frame to (or from) the FIFO. It will probably use ++ * efficient burst modes to access memory. ++ */ ++void edma_set_transfer_params(unsigned slot, ++ u16 acnt, u16 bcnt, u16 ccnt, ++ u16 bcnt_rld, enum sync_dimension sync_mode) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(slot); ++ slot = EDMA_CHAN_SLOT(slot); ++ ++ if (slot < edma_cc[ctlr]->num_slots) { ++ edma_parm_modify(ctlr, PARM_LINK_BCNTRLD, slot, ++ 0x0000ffff, bcnt_rld << 16); ++ if (sync_mode == ASYNC) ++ edma_parm_and(ctlr, PARM_OPT, slot, ~SYNCDIM); ++ else ++ edma_parm_or(ctlr, PARM_OPT, slot, SYNCDIM); ++ /* Set the acount, bcount, ccount registers */ ++ edma_parm_write(ctlr, PARM_A_B_CNT, slot, (bcnt << 16) | acnt); ++ edma_parm_write(ctlr, PARM_CCNT, slot, ccnt); ++ } ++} ++EXPORT_SYMBOL(edma_set_transfer_params); ++ ++/** ++ * edma_link - link one parameter RAM slot to another ++ * @from: parameter RAM slot originating the link ++ * @to: parameter RAM slot which is the link target ++ * ++ * The originating slot should not be part of any active DMA transfer. ++ */ ++void edma_link(unsigned from, unsigned to) ++{ ++ unsigned ctlr_from, ctlr_to; ++ ++ ctlr_from = EDMA_CTLR(from); ++ from = EDMA_CHAN_SLOT(from); ++ ctlr_to = EDMA_CTLR(to); ++ to = EDMA_CHAN_SLOT(to); ++ ++ if (from >= edma_cc[ctlr_from]->num_slots) ++ return; ++ if (to >= edma_cc[ctlr_to]->num_slots) ++ return; ++ edma_parm_modify(ctlr_from, PARM_LINK_BCNTRLD, from, 0xffff0000, ++ PARM_OFFSET(to)); ++} ++EXPORT_SYMBOL(edma_link); ++ ++/** ++ * edma_unlink - cut link from one parameter RAM slot ++ * @from: parameter RAM slot originating the link ++ * ++ * The originating slot should not be part of any active DMA transfer. ++ * Its link is set to 0xffff. ++ */ ++void edma_unlink(unsigned from) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(from); ++ from = EDMA_CHAN_SLOT(from); ++ ++ if (from >= edma_cc[ctlr]->num_slots) ++ return; ++ edma_parm_or(ctlr, PARM_LINK_BCNTRLD, from, 0xffff); ++} ++EXPORT_SYMBOL(edma_unlink); ++ ++/*-----------------------------------------------------------------------*/ ++ ++/* Parameter RAM operations (ii) -- read/write whole parameter sets */ ++ ++/** ++ * edma_write_slot - write parameter RAM data for slot ++ * @slot: number of parameter RAM slot being modified ++ * @param: data to be written into parameter RAM slot ++ * ++ * Use this to assign all parameters of a transfer at once. This ++ * allows more efficient setup of transfers than issuing multiple ++ * calls to set up those parameters in small pieces, and provides ++ * complete control over all transfer options. ++ */ ++void edma_write_slot(unsigned slot, const struct edmacc_param *param) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(slot); ++ slot = EDMA_CHAN_SLOT(slot); ++ ++ if (slot >= edma_cc[ctlr]->num_slots) ++ return; ++ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot), param, ++ PARM_SIZE); ++} ++EXPORT_SYMBOL(edma_write_slot); ++ ++/** ++ * edma_read_slot - read parameter RAM data from slot ++ * @slot: number of parameter RAM slot being copied ++ * @param: where to store copy of parameter RAM data ++ * ++ * Use this to read data from a parameter RAM slot, perhaps to ++ * save them as a template for later reuse. ++ */ ++void edma_read_slot(unsigned slot, struct edmacc_param *param) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(slot); ++ slot = EDMA_CHAN_SLOT(slot); ++ ++ if (slot >= edma_cc[ctlr]->num_slots) ++ return; ++ memcpy_fromio(param, edmacc_regs_base[ctlr] + PARM_OFFSET(slot), ++ PARM_SIZE); ++} ++EXPORT_SYMBOL(edma_read_slot); ++ ++/*-----------------------------------------------------------------------*/ ++ ++/* Various EDMA channel control operations */ ++ ++/** ++ * edma_pause - pause dma on a channel ++ * @channel: on which edma_start() has been called ++ * ++ * This temporarily disables EDMA hardware events on the specified channel, ++ * preventing them from triggering new transfers on its behalf ++ */ ++void edma_pause(unsigned channel) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(channel); ++ channel = EDMA_CHAN_SLOT(channel); ++ ++ if (channel < edma_cc[ctlr]->num_channels) { ++ unsigned int mask = BIT(channel & 0x1f); ++ ++ edma_shadow0_write_array(ctlr, SH_EECR, channel >> 5, mask); ++ } ++} ++EXPORT_SYMBOL(edma_pause); ++ ++/** ++ * edma_resume - resumes dma on a paused channel ++ * @channel: on which edma_pause() has been called ++ * ++ * This re-enables EDMA hardware events on the specified channel. ++ */ ++void edma_resume(unsigned channel) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(channel); ++ channel = EDMA_CHAN_SLOT(channel); ++ ++ if (channel < edma_cc[ctlr]->num_channels) { ++ unsigned int mask = BIT(channel & 0x1f); ++ ++ edma_shadow0_write_array(ctlr, SH_EESR, channel >> 5, mask); ++ } ++} ++EXPORT_SYMBOL(edma_resume); ++ ++/** ++ * edma_start - start dma on a channel ++ * @channel: channel being activated ++ * ++ * Channels with event associations will be triggered by their hardware ++ * events, and channels without such associations will be triggered by ++ * software. (At this writing there is no interface for using software ++ * triggers except with channels that don't support hardware triggers.) ++ * ++ * Returns zero on success, else negative errno. ++ */ ++int edma_start(unsigned channel) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(channel); ++ channel = EDMA_CHAN_SLOT(channel); ++ ++ if (channel < edma_cc[ctlr]->num_channels) { ++ int j = channel >> 5; ++ unsigned int mask = BIT(channel & 0x1f); ++ ++ /* EDMA channels without event association */ ++ if (test_bit(channel, edma_cc[ctlr]->edma_unused)) { ++ pr_debug("EDMA: ESR%d %08x\n", j, ++ edma_shadow0_read_array(ctlr, SH_ESR, j)); ++ edma_shadow0_write_array(ctlr, SH_ESR, j, mask); ++ return 0; ++ } ++ ++ /* EDMA channel with event association */ ++ pr_debug("EDMA: ER%d %08x\n", j, ++ edma_shadow0_read_array(ctlr, SH_ER, j)); ++ /* Clear any pending event or error */ ++ edma_write_array(ctlr, EDMA_ECR, j, mask); ++ edma_write_array(ctlr, EDMA_EMCR, j, mask); ++ /* Clear any SER */ ++ edma_shadow0_write_array(ctlr, SH_SECR, j, mask); ++ edma_shadow0_write_array(ctlr, SH_EESR, j, mask); ++ pr_debug("EDMA: EER%d %08x\n", j, ++ edma_shadow0_read_array(ctlr, SH_EER, j)); ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++EXPORT_SYMBOL(edma_start); ++ ++/** ++ * edma_stop - stops dma on the channel passed ++ * @channel: channel being deactivated ++ * ++ * When @lch is a channel, any active transfer is paused and ++ * all pending hardware events are cleared. The current transfer ++ * may not be resumed, and the channel's Parameter RAM should be ++ * reinitialized before being reused. ++ */ ++void edma_stop(unsigned channel) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(channel); ++ channel = EDMA_CHAN_SLOT(channel); ++ ++ if (channel < edma_cc[ctlr]->num_channels) { ++ int j = channel >> 5; ++ unsigned int mask = BIT(channel & 0x1f); ++ ++ edma_shadow0_write_array(ctlr, SH_EECR, j, mask); ++ edma_shadow0_write_array(ctlr, SH_ECR, j, mask); ++ edma_shadow0_write_array(ctlr, SH_SECR, j, mask); ++ edma_write_array(ctlr, EDMA_EMCR, j, mask); ++ ++ pr_debug("EDMA: EER%d %08x\n", j, ++ edma_shadow0_read_array(ctlr, SH_EER, j)); ++ ++ /* REVISIT: consider guarding against inappropriate event ++ * chaining by overwriting with dummy_paramset. ++ */ ++ } ++} ++EXPORT_SYMBOL(edma_stop); ++ ++/****************************************************************************** ++ * ++ * It cleans ParamEntry qand bring back EDMA to initial state if media has ++ * been removed before EDMA has finished.It is usedful for removable media. ++ * Arguments: ++ * ch_no - channel no ++ * ++ * Return: zero on success, or corresponding error no on failure ++ * ++ * FIXME this should not be needed ... edma_stop() should suffice. ++ * ++ *****************************************************************************/ ++ ++void edma_clean_channel(unsigned channel) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(channel); ++ channel = EDMA_CHAN_SLOT(channel); ++ ++ if (channel < edma_cc[ctlr]->num_channels) { ++ int j = (channel >> 5); ++ unsigned int mask = BIT(channel & 0x1f); ++ ++ pr_debug("EDMA: EMR%d %08x\n", j, ++ edma_read_array(ctlr, EDMA_EMR, j)); ++ edma_shadow0_write_array(ctlr, SH_ECR, j, mask); ++ /* Clear the corresponding EMR bits */ ++ edma_write_array(ctlr, EDMA_EMCR, j, mask); ++ /* Clear any SER */ ++ edma_shadow0_write_array(ctlr, SH_SECR, j, mask); ++ edma_write(ctlr, EDMA_CCERRCLR, BIT(16) | BIT(1) | BIT(0)); ++ } ++} ++EXPORT_SYMBOL(edma_clean_channel); ++ ++/* ++ * edma_clear_event - clear an outstanding event on the DMA channel ++ * Arguments: ++ * channel - channel number ++ */ ++void edma_clear_event(unsigned channel) ++{ ++ unsigned ctlr; ++ ++ ctlr = EDMA_CTLR(channel); ++ channel = EDMA_CHAN_SLOT(channel); ++ ++ if (channel >= edma_cc[ctlr]->num_channels) ++ return; ++ if (channel < 32) ++ edma_write(ctlr, EDMA_ECR, BIT(channel)); ++ else ++ edma_write(ctlr, EDMA_ECRH, BIT(channel - 32)); ++} ++EXPORT_SYMBOL(edma_clear_event); ++ ++/*-----------------------------------------------------------------------*/ ++ ++static int __init edma_probe(struct platform_device *pdev) ++{ ++ struct edma_soc_info **info = pdev->dev.platform_data; ++ const s8 (*queue_priority_mapping)[2]; ++ const s8 (*queue_tc_mapping)[2]; ++ int i, j, off, ln, found = 0; ++ int status = -1; ++ const s16 (*rsv_chans)[2]; ++ const s16 (*rsv_slots)[2]; ++ int irq[EDMA_MAX_CC] = {0, 0}; ++ int err_irq[EDMA_MAX_CC] = {0, 0}; ++ struct resource *r[EDMA_MAX_CC] = {NULL}; ++ resource_size_t len[EDMA_MAX_CC]; ++ char res_name[10]; ++ char irq_name[10]; ++ ++ if (!info) ++ return -ENODEV; ++ ++ for (j = 0; j < EDMA_MAX_CC; j++) { ++ sprintf(res_name, "edma_cc%d", j); ++ r[j] = platform_get_resource_byname(pdev, IORESOURCE_MEM, ++ res_name); ++ if (!r[j] || !info[j]) { ++ if (found) ++ break; ++ else ++ return -ENODEV; ++ } else { ++ found = 1; ++ } ++ ++ len[j] = resource_size(r[j]); ++ ++ r[j] = request_mem_region(r[j]->start, len[j], ++ dev_name(&pdev->dev)); ++ if (!r[j]) { ++ status = -EBUSY; ++ goto fail1; ++ } ++ ++ edmacc_regs_base[j] = ioremap(r[j]->start, len[j]); ++ if (!edmacc_regs_base[j]) { ++ status = -EBUSY; ++ goto fail1; ++ } ++ ++ edma_cc[j] = kzalloc(sizeof(struct edma), GFP_KERNEL); ++ if (!edma_cc[j]) { ++ status = -ENOMEM; ++ goto fail1; ++ } ++ ++ edma_cc[j]->num_channels = min_t(unsigned, info[j]->n_channel, ++ EDMA_MAX_DMACH); ++ edma_cc[j]->num_slots = min_t(unsigned, info[j]->n_slot, ++ EDMA_MAX_PARAMENTRY); ++ edma_cc[j]->num_cc = min_t(unsigned, info[j]->n_cc, ++ EDMA_MAX_CC); ++ ++ edma_cc[j]->default_queue = info[j]->default_queue; ++ ++ dev_dbg(&pdev->dev, "DMA REG BASE ADDR=%p\n", ++ edmacc_regs_base[j]); ++ ++ for (i = 0; i < edma_cc[j]->num_slots; i++) ++ memcpy_toio(edmacc_regs_base[j] + PARM_OFFSET(i), ++ &dummy_paramset, PARM_SIZE); ++ ++ /* Mark all channels as unused */ ++ memset(edma_cc[j]->edma_unused, 0xff, ++ sizeof(edma_cc[j]->edma_unused)); ++ ++ if (info[j]->rsv) { ++ ++ /* Clear the reserved channels in unused list */ ++ rsv_chans = info[j]->rsv->rsv_chans; ++ if (rsv_chans) { ++ for (i = 0; rsv_chans[i][0] != -1; i++) { ++ off = rsv_chans[i][0]; ++ ln = rsv_chans[i][1]; ++ clear_bits(off, ln, ++ edma_cc[j]->edma_unused); ++ } ++ } ++ ++ /* Set the reserved slots in inuse list */ ++ rsv_slots = info[j]->rsv->rsv_slots; ++ if (rsv_slots) { ++ for (i = 0; rsv_slots[i][0] != -1; i++) { ++ off = rsv_slots[i][0]; ++ ln = rsv_slots[i][1]; ++ set_bits(off, ln, ++ edma_cc[j]->edma_inuse); ++ } ++ } ++ } ++ ++ sprintf(irq_name, "edma%d", j); ++ irq[j] = platform_get_irq_byname(pdev, irq_name); ++ edma_cc[j]->irq_res_start = irq[j]; ++ status = request_irq(irq[j], dma_irq_handler, 0, "edma", ++ &pdev->dev); ++ if (status < 0) { ++ dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n", ++ irq[j], status); ++ goto fail; ++ } ++ ++ sprintf(irq_name, "edma%d_err", j); ++ err_irq[j] = platform_get_irq_byname(pdev, irq_name); ++ edma_cc[j]->irq_res_end = err_irq[j]; ++ status = request_irq(err_irq[j], dma_ccerr_handler, 0, ++ "edma_error", &pdev->dev); ++ if (status < 0) { ++ dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n", ++ err_irq[j], status); ++ goto fail; ++ } ++ ++ for (i = 0; i < edma_cc[j]->num_channels; i++) ++ map_dmach_queue(j, i, info[j]->default_queue); ++ ++ queue_tc_mapping = info[j]->queue_tc_mapping; ++ queue_priority_mapping = info[j]->queue_priority_mapping; ++ ++ /* Event queue to TC mapping */ ++ for (i = 0; queue_tc_mapping[i][0] != -1; i++) ++ map_queue_tc(j, queue_tc_mapping[i][0], ++ queue_tc_mapping[i][1]); ++ ++ /* Event queue priority mapping */ ++ for (i = 0; queue_priority_mapping[i][0] != -1; i++) ++ assign_priority_to_queue(j, ++ queue_priority_mapping[i][0], ++ queue_priority_mapping[i][1]); ++ ++ /* Map the channel to param entry if channel mapping logic ++ * exist ++ */ ++ if (edma_read(j, EDMA_CCCFG) & CHMAP_EXIST) ++ map_dmach_param(j); ++ ++ for (i = 0; i < info[j]->n_region; i++) { ++ edma_write_array2(j, EDMA_DRAE, i, 0, 0x0); ++ edma_write_array2(j, EDMA_DRAE, i, 1, 0x0); ++ edma_write_array(j, EDMA_QRAE, i, 0x0); ++ } ++ arch_num_cc++; ++ } ++ ++ if (tc_errs_handled) { ++ status = request_irq(IRQ_TCERRINT0, dma_tc0err_handler, 0, ++ "edma_tc0", &pdev->dev); ++ if (status < 0) { ++ dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n", ++ IRQ_TCERRINT0, status); ++ return status; ++ } ++ status = request_irq(IRQ_TCERRINT, dma_tc1err_handler, 0, ++ "edma_tc1", &pdev->dev); ++ if (status < 0) { ++ dev_dbg(&pdev->dev, "request_irq %d --> %d\n", ++ IRQ_TCERRINT, status); ++ return status; ++ } ++ } ++ ++ return 0; ++ ++fail: ++ for (i = 0; i < EDMA_MAX_CC; i++) { ++ if (err_irq[i]) ++ free_irq(err_irq[i], &pdev->dev); ++ if (irq[i]) ++ free_irq(irq[i], &pdev->dev); ++ } ++fail1: ++ for (i = 0; i < EDMA_MAX_CC; i++) { ++ if (r[i]) ++ release_mem_region(r[i]->start, len[i]); ++ if (edmacc_regs_base[i]) ++ iounmap(edmacc_regs_base[i]); ++ kfree(edma_cc[i]); ++ } ++ return status; ++} ++ ++ ++static struct platform_driver edma_driver = { ++ .driver.name = "edma", ++}; ++ ++static int __init edma_init(void) ++{ ++ return platform_driver_probe(&edma_driver, edma_probe); ++} ++arch_initcall(edma_init); ++ +diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile +index 2227eff..97c639e 100644 +--- a/arch/arm/mach-davinci/Makefile ++++ b/arch/arm/mach-davinci/Makefile +@@ -5,7 +5,7 @@ + + # Common objects + obj-y := time.o clock.o serial.o psc.o \ +- dma.o usb.o common.o sram.o aemif.o ++ usb.o common.o sram.o aemif.o + + obj-$(CONFIG_DAVINCI_MUX) += mux.o + +diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c +index be30997..86f55ba 100644 +--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c ++++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c +@@ -26,12 +26,12 @@ + #include <linux/input.h> + #include <linux/input/matrix_keypad.h> + #include <linux/spi/spi.h> ++#include <linux/platform_data/edma.h> + + #include <asm/mach/arch.h> + #include <asm/mach-types.h> + + #include <mach/irqs.h> +-#include <mach/edma.h> + #include <mach/mux.h> + #include <mach/cp_intc.h> + #include <mach/tnetv107x.h> +diff --git a/arch/arm/mach-davinci/davinci.h b/arch/arm/mach-davinci/davinci.h +index 12d544b..d26a6bc 100644 +--- a/arch/arm/mach-davinci/davinci.h ++++ b/arch/arm/mach-davinci/davinci.h +@@ -23,9 +23,9 @@ + #include <linux/platform_device.h> + #include <linux/spi/spi.h> + #include <linux/platform_data/davinci_asp.h> ++#include <linux/platform_data/edma.h> + #include <linux/platform_data/keyscan-davinci.h> + #include <mach/hardware.h> +-#include <mach/edma.h> + + #include <media/davinci/vpfe_capture.h> + #include <media/davinci/vpif_types.h> +diff --git a/arch/arm/mach-davinci/devices-tnetv107x.c b/arch/arm/mach-davinci/devices-tnetv107x.c +index 29b17f7..59efd7f 100644 +--- a/arch/arm/mach-davinci/devices-tnetv107x.c ++++ b/arch/arm/mach-davinci/devices-tnetv107x.c +@@ -18,10 +18,10 @@ + #include <linux/dma-mapping.h> + #include <linux/clk.h> + #include <linux/slab.h> ++#include <linux/platform_data/edma.h> + + #include <mach/common.h> + #include <mach/irqs.h> +-#include <mach/edma.h> + #include <mach/tnetv107x.h> + + #include "clock.h" +diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c +index 4c48a36..f45d591 100644 +--- a/arch/arm/mach-davinci/devices.c ++++ b/arch/arm/mach-davinci/devices.c +@@ -19,9 +19,10 @@ + #include <mach/irqs.h> + #include <mach/cputype.h> + #include <mach/mux.h> +-#include <mach/edma.h> + #include <linux/platform_data/mmc-davinci.h> + #include <mach/time.h> ++#include <linux/platform_data/edma.h> ++ + + #include "davinci.h" + #include "clock.h" +@@ -141,10 +142,10 @@ static struct resource mmcsd0_resources[] = { + }, + /* DMA channels: RX, then TX */ + { +- .start = EDMA_CTLR_CHAN(0, DAVINCI_DMA_MMCRXEVT), ++ .start = EDMA_CTLR_CHAN(0, 26), + .flags = IORESOURCE_DMA, + }, { +- .start = EDMA_CTLR_CHAN(0, DAVINCI_DMA_MMCTXEVT), ++ .start = EDMA_CTLR_CHAN(0, 27), + .flags = IORESOURCE_DMA, + }, + }; +diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c +index a255434..b165c27 100644 +--- a/arch/arm/mach-davinci/dm355.c ++++ b/arch/arm/mach-davinci/dm355.c +@@ -19,7 +19,6 @@ + #include <asm/mach/map.h> + + #include <mach/cputype.h> +-#include <mach/edma.h> + #include <mach/psc.h> + #include <mach/mux.h> + #include <mach/irqs.h> +@@ -28,6 +27,7 @@ + #include <mach/common.h> + #include <linux/platform_data/spi-davinci.h> + #include <mach/gpio-davinci.h> ++#include <linux/platform_data/edma.h> + + #include "davinci.h" + #include "clock.h" +diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c +index b680c83..a611716 100644 +--- a/arch/arm/mach-davinci/dm365.c ++++ b/arch/arm/mach-davinci/dm365.c +@@ -18,11 +18,11 @@ + #include <linux/platform_device.h> + #include <linux/dma-mapping.h> + #include <linux/spi/spi.h> ++#include <linux/platform_data/edma.h> + + #include <asm/mach/map.h> + + #include <mach/cputype.h> +-#include <mach/edma.h> + #include <mach/psc.h> + #include <mach/mux.h> + #include <mach/irqs.h> +diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c +index cd0c8b1..90f5639 100644 +--- a/arch/arm/mach-davinci/dm644x.c ++++ b/arch/arm/mach-davinci/dm644x.c +@@ -12,11 +12,11 @@ + #include <linux/clk.h> + #include <linux/serial_8250.h> + #include <linux/platform_device.h> ++#include <linux/platform_data/edma.h> + + #include <asm/mach/map.h> + + #include <mach/cputype.h> +-#include <mach/edma.h> + #include <mach/irqs.h> + #include <mach/psc.h> + #include <mach/mux.h> +diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c +index 97c0f8e..08f9dab 100644 +--- a/arch/arm/mach-davinci/dm646x.c ++++ b/arch/arm/mach-davinci/dm646x.c +@@ -13,11 +13,11 @@ + #include <linux/clk.h> + #include <linux/serial_8250.h> + #include <linux/platform_device.h> ++#include <linux/platform_data/edma.h> + + #include <asm/mach/map.h> + + #include <mach/cputype.h> +-#include <mach/edma.h> + #include <mach/irqs.h> + #include <mach/psc.h> + #include <mach/mux.h> +diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c +deleted file mode 100644 +index a685e97..0000000 +--- a/arch/arm/mach-davinci/dma.c ++++ /dev/null +@@ -1,1588 +0,0 @@ +-/* +- * EDMA3 support for DaVinci +- * +- * Copyright (C) 2006-2009 Texas Instruments. +- * +- * 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 <linux/kernel.h> +-#include <linux/init.h> +-#include <linux/module.h> +-#include <linux/interrupt.h> +-#include <linux/platform_device.h> +-#include <linux/io.h> +-#include <linux/slab.h> +- +-#include <mach/edma.h> +- +-/* Offsets matching "struct edmacc_param" */ +-#define PARM_OPT 0x00 +-#define PARM_SRC 0x04 +-#define PARM_A_B_CNT 0x08 +-#define PARM_DST 0x0c +-#define PARM_SRC_DST_BIDX 0x10 +-#define PARM_LINK_BCNTRLD 0x14 +-#define PARM_SRC_DST_CIDX 0x18 +-#define PARM_CCNT 0x1c +- +-#define PARM_SIZE 0x20 +- +-/* Offsets for EDMA CC global channel registers and their shadows */ +-#define SH_ER 0x00 /* 64 bits */ +-#define SH_ECR 0x08 /* 64 bits */ +-#define SH_ESR 0x10 /* 64 bits */ +-#define SH_CER 0x18 /* 64 bits */ +-#define SH_EER 0x20 /* 64 bits */ +-#define SH_EECR 0x28 /* 64 bits */ +-#define SH_EESR 0x30 /* 64 bits */ +-#define SH_SER 0x38 /* 64 bits */ +-#define SH_SECR 0x40 /* 64 bits */ +-#define SH_IER 0x50 /* 64 bits */ +-#define SH_IECR 0x58 /* 64 bits */ +-#define SH_IESR 0x60 /* 64 bits */ +-#define SH_IPR 0x68 /* 64 bits */ +-#define SH_ICR 0x70 /* 64 bits */ +-#define SH_IEVAL 0x78 +-#define SH_QER 0x80 +-#define SH_QEER 0x84 +-#define SH_QEECR 0x88 +-#define SH_QEESR 0x8c +-#define SH_QSER 0x90 +-#define SH_QSECR 0x94 +-#define SH_SIZE 0x200 +- +-/* Offsets for EDMA CC global registers */ +-#define EDMA_REV 0x0000 +-#define EDMA_CCCFG 0x0004 +-#define EDMA_QCHMAP 0x0200 /* 8 registers */ +-#define EDMA_DMAQNUM 0x0240 /* 8 registers (4 on OMAP-L1xx) */ +-#define EDMA_QDMAQNUM 0x0260 +-#define EDMA_QUETCMAP 0x0280 +-#define EDMA_QUEPRI 0x0284 +-#define EDMA_EMR 0x0300 /* 64 bits */ +-#define EDMA_EMCR 0x0308 /* 64 bits */ +-#define EDMA_QEMR 0x0310 +-#define EDMA_QEMCR 0x0314 +-#define EDMA_CCERR 0x0318 +-#define EDMA_CCERRCLR 0x031c +-#define EDMA_EEVAL 0x0320 +-#define EDMA_DRAE 0x0340 /* 4 x 64 bits*/ +-#define EDMA_QRAE 0x0380 /* 4 registers */ +-#define EDMA_QUEEVTENTRY 0x0400 /* 2 x 16 registers */ +-#define EDMA_QSTAT 0x0600 /* 2 registers */ +-#define EDMA_QWMTHRA 0x0620 +-#define EDMA_QWMTHRB 0x0624 +-#define EDMA_CCSTAT 0x0640 +- +-#define EDMA_M 0x1000 /* global channel registers */ +-#define EDMA_ECR 0x1008 +-#define EDMA_ECRH 0x100C +-#define EDMA_SHADOW0 0x2000 /* 4 regions shadowing global channels */ +-#define EDMA_PARM 0x4000 /* 128 param entries */ +- +-#define PARM_OFFSET(param_no) (EDMA_PARM + ((param_no) << 5)) +- +-#define EDMA_DCHMAP 0x0100 /* 64 registers */ +-#define CHMAP_EXIST BIT(24) +- +-#define EDMA_MAX_DMACH 64 +-#define EDMA_MAX_PARAMENTRY 512 +- +-/*****************************************************************************/ +- +-static void __iomem *edmacc_regs_base[EDMA_MAX_CC]; +- +-static inline unsigned int edma_read(unsigned ctlr, int offset) +-{ +- return (unsigned int)__raw_readl(edmacc_regs_base[ctlr] + offset); +-} +- +-static inline void edma_write(unsigned ctlr, int offset, int val) +-{ +- __raw_writel(val, edmacc_regs_base[ctlr] + offset); +-} +-static inline void edma_modify(unsigned ctlr, int offset, unsigned and, +- unsigned or) +-{ +- unsigned val = edma_read(ctlr, offset); +- val &= and; +- val |= or; +- edma_write(ctlr, offset, val); +-} +-static inline void edma_and(unsigned ctlr, int offset, unsigned and) +-{ +- unsigned val = edma_read(ctlr, offset); +- val &= and; +- edma_write(ctlr, offset, val); +-} +-static inline void edma_or(unsigned ctlr, int offset, unsigned or) +-{ +- unsigned val = edma_read(ctlr, offset); +- val |= or; +- edma_write(ctlr, offset, val); +-} +-static inline unsigned int edma_read_array(unsigned ctlr, int offset, int i) +-{ +- return edma_read(ctlr, offset + (i << 2)); +-} +-static inline void edma_write_array(unsigned ctlr, int offset, int i, +- unsigned val) +-{ +- edma_write(ctlr, offset + (i << 2), val); +-} +-static inline void edma_modify_array(unsigned ctlr, int offset, int i, +- unsigned and, unsigned or) +-{ +- edma_modify(ctlr, offset + (i << 2), and, or); +-} +-static inline void edma_or_array(unsigned ctlr, int offset, int i, unsigned or) +-{ +- edma_or(ctlr, offset + (i << 2), or); +-} +-static inline void edma_or_array2(unsigned ctlr, int offset, int i, int j, +- unsigned or) +-{ +- edma_or(ctlr, offset + ((i*2 + j) << 2), or); +-} +-static inline void edma_write_array2(unsigned ctlr, int offset, int i, int j, +- unsigned val) +-{ +- edma_write(ctlr, offset + ((i*2 + j) << 2), val); +-} +-static inline unsigned int edma_shadow0_read(unsigned ctlr, int offset) +-{ +- return edma_read(ctlr, EDMA_SHADOW0 + offset); +-} +-static inline unsigned int edma_shadow0_read_array(unsigned ctlr, int offset, +- int i) +-{ +- return edma_read(ctlr, EDMA_SHADOW0 + offset + (i << 2)); +-} +-static inline void edma_shadow0_write(unsigned ctlr, int offset, unsigned val) +-{ +- edma_write(ctlr, EDMA_SHADOW0 + offset, val); +-} +-static inline void edma_shadow0_write_array(unsigned ctlr, int offset, int i, +- unsigned val) +-{ +- edma_write(ctlr, EDMA_SHADOW0 + offset + (i << 2), val); +-} +-static inline unsigned int edma_parm_read(unsigned ctlr, int offset, +- int param_no) +-{ +- return edma_read(ctlr, EDMA_PARM + offset + (param_no << 5)); +-} +-static inline void edma_parm_write(unsigned ctlr, int offset, int param_no, +- unsigned val) +-{ +- edma_write(ctlr, EDMA_PARM + offset + (param_no << 5), val); +-} +-static inline void edma_parm_modify(unsigned ctlr, int offset, int param_no, +- unsigned and, unsigned or) +-{ +- edma_modify(ctlr, EDMA_PARM + offset + (param_no << 5), and, or); +-} +-static inline void edma_parm_and(unsigned ctlr, int offset, int param_no, +- unsigned and) +-{ +- edma_and(ctlr, EDMA_PARM + offset + (param_no << 5), and); +-} +-static inline void edma_parm_or(unsigned ctlr, int offset, int param_no, +- unsigned or) +-{ +- edma_or(ctlr, EDMA_PARM + offset + (param_no << 5), or); +-} +- +-static inline void set_bits(int offset, int len, unsigned long *p) +-{ +- for (; len > 0; len--) +- set_bit(offset + (len - 1), p); +-} +- +-static inline void clear_bits(int offset, int len, unsigned long *p) +-{ +- for (; len > 0; len--) +- clear_bit(offset + (len - 1), p); +-} +- +-/*****************************************************************************/ +- +-/* actual number of DMA channels and slots on this silicon */ +-struct edma { +- /* how many dma resources of each type */ +- unsigned num_channels; +- unsigned num_region; +- unsigned num_slots; +- unsigned num_tc; +- unsigned num_cc; +- enum dma_event_q default_queue; +- +- /* list of channels with no even trigger; terminated by "-1" */ +- const s8 *noevent; +- +- /* The edma_inuse bit for each PaRAM slot is clear unless the +- * channel is in use ... by ARM or DSP, for QDMA, or whatever. +- */ +- DECLARE_BITMAP(edma_inuse, EDMA_MAX_PARAMENTRY); +- +- /* The edma_unused bit for each channel is clear unless +- * it is not being used on this platform. It uses a bit +- * of SOC-specific initialization code. +- */ +- DECLARE_BITMAP(edma_unused, EDMA_MAX_DMACH); +- +- unsigned irq_res_start; +- unsigned irq_res_end; +- +- struct dma_interrupt_data { +- void (*callback)(unsigned channel, unsigned short ch_status, +- void *data); +- void *data; +- } intr_data[EDMA_MAX_DMACH]; +-}; +- +-static struct edma *edma_cc[EDMA_MAX_CC]; +-static int arch_num_cc; +- +-/* dummy param set used to (re)initialize parameter RAM slots */ +-static const struct edmacc_param dummy_paramset = { +- .link_bcntrld = 0xffff, +- .ccnt = 1, +-}; +- +-/*****************************************************************************/ +- +-static void map_dmach_queue(unsigned ctlr, unsigned ch_no, +- enum dma_event_q queue_no) +-{ +- int bit = (ch_no & 0x7) * 4; +- +- /* default to low priority queue */ +- if (queue_no == EVENTQ_DEFAULT) +- queue_no = edma_cc[ctlr]->default_queue; +- +- queue_no &= 7; +- edma_modify_array(ctlr, EDMA_DMAQNUM, (ch_no >> 3), +- ~(0x7 << bit), queue_no << bit); +-} +- +-static void __init map_queue_tc(unsigned ctlr, int queue_no, int tc_no) +-{ +- int bit = queue_no * 4; +- edma_modify(ctlr, EDMA_QUETCMAP, ~(0x7 << bit), ((tc_no & 0x7) << bit)); +-} +- +-static void __init assign_priority_to_queue(unsigned ctlr, int queue_no, +- int priority) +-{ +- int bit = queue_no * 4; +- edma_modify(ctlr, EDMA_QUEPRI, ~(0x7 << bit), +- ((priority & 0x7) << bit)); +-} +- +-/** +- * map_dmach_param - Maps channel number to param entry number +- * +- * This maps the dma channel number to param entry numberter. In +- * other words using the DMA channel mapping registers a param entry +- * can be mapped to any channel +- * +- * Callers are responsible for ensuring the channel mapping logic is +- * included in that particular EDMA variant (Eg : dm646x) +- * +- */ +-static void __init map_dmach_param(unsigned ctlr) +-{ +- int i; +- for (i = 0; i < EDMA_MAX_DMACH; i++) +- edma_write_array(ctlr, EDMA_DCHMAP , i , (i << 5)); +-} +- +-static inline void +-setup_dma_interrupt(unsigned lch, +- void (*callback)(unsigned channel, u16 ch_status, void *data), +- void *data) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(lch); +- lch = EDMA_CHAN_SLOT(lch); +- +- if (!callback) +- edma_shadow0_write_array(ctlr, SH_IECR, lch >> 5, +- BIT(lch & 0x1f)); +- +- edma_cc[ctlr]->intr_data[lch].callback = callback; +- edma_cc[ctlr]->intr_data[lch].data = data; +- +- if (callback) { +- edma_shadow0_write_array(ctlr, SH_ICR, lch >> 5, +- BIT(lch & 0x1f)); +- edma_shadow0_write_array(ctlr, SH_IESR, lch >> 5, +- BIT(lch & 0x1f)); +- } +-} +- +-static int irq2ctlr(int irq) +-{ +- if (irq >= edma_cc[0]->irq_res_start && irq <= edma_cc[0]->irq_res_end) +- return 0; +- else if (irq >= edma_cc[1]->irq_res_start && +- irq <= edma_cc[1]->irq_res_end) +- return 1; +- +- return -1; +-} +- +-/****************************************************************************** +- * +- * DMA interrupt handler +- * +- *****************************************************************************/ +-static irqreturn_t dma_irq_handler(int irq, void *data) +-{ +- int ctlr; +- u32 sh_ier; +- u32 sh_ipr; +- u32 bank; +- +- ctlr = irq2ctlr(irq); +- if (ctlr < 0) +- return IRQ_NONE; +- +- dev_dbg(data, "dma_irq_handler\n"); +- +- sh_ipr = edma_shadow0_read_array(ctlr, SH_IPR, 0); +- if (!sh_ipr) { +- sh_ipr = edma_shadow0_read_array(ctlr, SH_IPR, 1); +- if (!sh_ipr) +- return IRQ_NONE; +- sh_ier = edma_shadow0_read_array(ctlr, SH_IER, 1); +- bank = 1; +- } else { +- sh_ier = edma_shadow0_read_array(ctlr, SH_IER, 0); +- bank = 0; +- } +- +- do { +- u32 slot; +- u32 channel; +- +- dev_dbg(data, "IPR%d %08x\n", bank, sh_ipr); +- +- slot = __ffs(sh_ipr); +- sh_ipr &= ~(BIT(slot)); +- +- if (sh_ier & BIT(slot)) { +- channel = (bank << 5) | slot; +- /* Clear the corresponding IPR bits */ +- edma_shadow0_write_array(ctlr, SH_ICR, bank, +- BIT(slot)); +- if (edma_cc[ctlr]->intr_data[channel].callback) +- edma_cc[ctlr]->intr_data[channel].callback( +- channel, DMA_COMPLETE, +- edma_cc[ctlr]->intr_data[channel].data); +- } +- } while (sh_ipr); +- +- edma_shadow0_write(ctlr, SH_IEVAL, 1); +- return IRQ_HANDLED; +-} +- +-/****************************************************************************** +- * +- * DMA error interrupt handler +- * +- *****************************************************************************/ +-static irqreturn_t dma_ccerr_handler(int irq, void *data) +-{ +- int i; +- int ctlr; +- unsigned int cnt = 0; +- +- ctlr = irq2ctlr(irq); +- if (ctlr < 0) +- return IRQ_NONE; +- +- dev_dbg(data, "dma_ccerr_handler\n"); +- +- if ((edma_read_array(ctlr, EDMA_EMR, 0) == 0) && +- (edma_read_array(ctlr, EDMA_EMR, 1) == 0) && +- (edma_read(ctlr, EDMA_QEMR) == 0) && +- (edma_read(ctlr, EDMA_CCERR) == 0)) +- return IRQ_NONE; +- +- while (1) { +- int j = -1; +- if (edma_read_array(ctlr, EDMA_EMR, 0)) +- j = 0; +- else if (edma_read_array(ctlr, EDMA_EMR, 1)) +- j = 1; +- if (j >= 0) { +- dev_dbg(data, "EMR%d %08x\n", j, +- edma_read_array(ctlr, EDMA_EMR, j)); +- for (i = 0; i < 32; i++) { +- int k = (j << 5) + i; +- if (edma_read_array(ctlr, EDMA_EMR, j) & +- BIT(i)) { +- /* Clear the corresponding EMR bits */ +- edma_write_array(ctlr, EDMA_EMCR, j, +- BIT(i)); +- /* Clear any SER */ +- edma_shadow0_write_array(ctlr, SH_SECR, +- j, BIT(i)); +- if (edma_cc[ctlr]->intr_data[k]. +- callback) { +- edma_cc[ctlr]->intr_data[k]. +- callback(k, +- DMA_CC_ERROR, +- edma_cc[ctlr]->intr_data +- [k].data); +- } +- } +- } +- } else if (edma_read(ctlr, EDMA_QEMR)) { +- dev_dbg(data, "QEMR %02x\n", +- edma_read(ctlr, EDMA_QEMR)); +- for (i = 0; i < 8; i++) { +- if (edma_read(ctlr, EDMA_QEMR) & BIT(i)) { +- /* Clear the corresponding IPR bits */ +- edma_write(ctlr, EDMA_QEMCR, BIT(i)); +- edma_shadow0_write(ctlr, SH_QSECR, +- BIT(i)); +- +- /* NOTE: not reported!! */ +- } +- } +- } else if (edma_read(ctlr, EDMA_CCERR)) { +- dev_dbg(data, "CCERR %08x\n", +- edma_read(ctlr, EDMA_CCERR)); +- /* FIXME: CCERR.BIT(16) ignored! much better +- * to just write CCERRCLR with CCERR value... +- */ +- for (i = 0; i < 8; i++) { +- if (edma_read(ctlr, EDMA_CCERR) & BIT(i)) { +- /* Clear the corresponding IPR bits */ +- edma_write(ctlr, EDMA_CCERRCLR, BIT(i)); +- +- /* NOTE: not reported!! */ +- } +- } +- } +- if ((edma_read_array(ctlr, EDMA_EMR, 0) == 0) && +- (edma_read_array(ctlr, EDMA_EMR, 1) == 0) && +- (edma_read(ctlr, EDMA_QEMR) == 0) && +- (edma_read(ctlr, EDMA_CCERR) == 0)) +- break; +- cnt++; +- if (cnt > 10) +- break; +- } +- edma_write(ctlr, EDMA_EEVAL, 1); +- return IRQ_HANDLED; +-} +- +-/****************************************************************************** +- * +- * Transfer controller error interrupt handlers +- * +- *****************************************************************************/ +- +-#define tc_errs_handled false /* disabled as long as they're NOPs */ +- +-static irqreturn_t dma_tc0err_handler(int irq, void *data) +-{ +- dev_dbg(data, "dma_tc0err_handler\n"); +- return IRQ_HANDLED; +-} +- +-static irqreturn_t dma_tc1err_handler(int irq, void *data) +-{ +- dev_dbg(data, "dma_tc1err_handler\n"); +- return IRQ_HANDLED; +-} +- +-static int reserve_contiguous_slots(int ctlr, unsigned int id, +- unsigned int num_slots, +- unsigned int start_slot) +-{ +- int i, j; +- unsigned int count = num_slots; +- int stop_slot = start_slot; +- DECLARE_BITMAP(tmp_inuse, EDMA_MAX_PARAMENTRY); +- +- for (i = start_slot; i < edma_cc[ctlr]->num_slots; ++i) { +- j = EDMA_CHAN_SLOT(i); +- if (!test_and_set_bit(j, edma_cc[ctlr]->edma_inuse)) { +- /* Record our current beginning slot */ +- if (count == num_slots) +- stop_slot = i; +- +- count--; +- set_bit(j, tmp_inuse); +- +- if (count == 0) +- break; +- } else { +- clear_bit(j, tmp_inuse); +- +- if (id == EDMA_CONT_PARAMS_FIXED_EXACT) { +- stop_slot = i; +- break; +- } else { +- count = num_slots; +- } +- } +- } +- +- /* +- * We have to clear any bits that we set +- * if we run out parameter RAM slots, i.e we do find a set +- * of contiguous parameter RAM slots but do not find the exact number +- * requested as we may reach the total number of parameter RAM slots +- */ +- if (i == edma_cc[ctlr]->num_slots) +- stop_slot = i; +- +- j = start_slot; +- for_each_set_bit_from(j, tmp_inuse, stop_slot) +- clear_bit(j, edma_cc[ctlr]->edma_inuse); +- +- if (count) +- return -EBUSY; +- +- for (j = i - num_slots + 1; j <= i; ++j) +- memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(j), +- &dummy_paramset, PARM_SIZE); +- +- return EDMA_CTLR_CHAN(ctlr, i - num_slots + 1); +-} +- +-static int prepare_unused_channel_list(struct device *dev, void *data) +-{ +- struct platform_device *pdev = to_platform_device(dev); +- int i, ctlr; +- +- for (i = 0; i < pdev->num_resources; i++) { +- if ((pdev->resource[i].flags & IORESOURCE_DMA) && +- (int)pdev->resource[i].start >= 0) { +- ctlr = EDMA_CTLR(pdev->resource[i].start); +- clear_bit(EDMA_CHAN_SLOT(pdev->resource[i].start), +- edma_cc[ctlr]->edma_unused); +- } +- } +- +- return 0; +-} +- +-/*-----------------------------------------------------------------------*/ +- +-static bool unused_chan_list_done; +- +-/* Resource alloc/free: dma channels, parameter RAM slots */ +- +-/** +- * edma_alloc_channel - allocate DMA channel and paired parameter RAM +- * @channel: specific channel to allocate; negative for "any unmapped channel" +- * @callback: optional; to be issued on DMA completion or errors +- * @data: passed to callback +- * @eventq_no: an EVENTQ_* constant, used to choose which Transfer +- * Controller (TC) executes requests using this channel. Use +- * EVENTQ_DEFAULT unless you really need a high priority queue. +- * +- * This allocates a DMA channel and its associated parameter RAM slot. +- * The parameter RAM is initialized to hold a dummy transfer. +- * +- * Normal use is to pass a specific channel number as @channel, to make +- * use of hardware events mapped to that channel. When the channel will +- * be used only for software triggering or event chaining, channels not +- * mapped to hardware events (or mapped to unused events) are preferable. +- * +- * DMA transfers start from a channel using edma_start(), or by +- * chaining. When the transfer described in that channel's parameter RAM +- * slot completes, that slot's data may be reloaded through a link. +- * +- * DMA errors are only reported to the @callback associated with the +- * channel driving that transfer, but transfer completion callbacks can +- * be sent to another channel under control of the TCC field in +- * the option word of the transfer's parameter RAM set. Drivers must not +- * use DMA transfer completion callbacks for channels they did not allocate. +- * (The same applies to TCC codes used in transfer chaining.) +- * +- * Returns the number of the channel, else negative errno. +- */ +-int edma_alloc_channel(int channel, +- void (*callback)(unsigned channel, u16 ch_status, void *data), +- void *data, +- enum dma_event_q eventq_no) +-{ +- unsigned i, done = 0, ctlr = 0; +- int ret = 0; +- +- if (!unused_chan_list_done) { +- /* +- * Scan all the platform devices to find out the EDMA channels +- * used and clear them in the unused list, making the rest +- * available for ARM usage. +- */ +- ret = bus_for_each_dev(&platform_bus_type, NULL, NULL, +- prepare_unused_channel_list); +- if (ret < 0) +- return ret; +- +- unused_chan_list_done = true; +- } +- +- if (channel >= 0) { +- ctlr = EDMA_CTLR(channel); +- channel = EDMA_CHAN_SLOT(channel); +- } +- +- if (channel < 0) { +- for (i = 0; i < arch_num_cc; i++) { +- channel = 0; +- for (;;) { +- channel = find_next_bit(edma_cc[i]->edma_unused, +- edma_cc[i]->num_channels, +- channel); +- if (channel == edma_cc[i]->num_channels) +- break; +- if (!test_and_set_bit(channel, +- edma_cc[i]->edma_inuse)) { +- done = 1; +- ctlr = i; +- break; +- } +- channel++; +- } +- if (done) +- break; +- } +- if (!done) +- return -ENOMEM; +- } else if (channel >= edma_cc[ctlr]->num_channels) { +- return -EINVAL; +- } else if (test_and_set_bit(channel, edma_cc[ctlr]->edma_inuse)) { +- return -EBUSY; +- } +- +- /* ensure access through shadow region 0 */ +- edma_or_array2(ctlr, EDMA_DRAE, 0, channel >> 5, BIT(channel & 0x1f)); +- +- /* ensure no events are pending */ +- edma_stop(EDMA_CTLR_CHAN(ctlr, channel)); +- memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(channel), +- &dummy_paramset, PARM_SIZE); +- +- if (callback) +- setup_dma_interrupt(EDMA_CTLR_CHAN(ctlr, channel), +- callback, data); +- +- map_dmach_queue(ctlr, channel, eventq_no); +- +- return EDMA_CTLR_CHAN(ctlr, channel); +-} +-EXPORT_SYMBOL(edma_alloc_channel); +- +- +-/** +- * edma_free_channel - deallocate DMA channel +- * @channel: dma channel returned from edma_alloc_channel() +- * +- * This deallocates the DMA channel and associated parameter RAM slot +- * allocated by edma_alloc_channel(). +- * +- * Callers are responsible for ensuring the channel is inactive, and +- * will not be reactivated by linking, chaining, or software calls to +- * edma_start(). +- */ +-void edma_free_channel(unsigned channel) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(channel); +- channel = EDMA_CHAN_SLOT(channel); +- +- if (channel >= edma_cc[ctlr]->num_channels) +- return; +- +- setup_dma_interrupt(channel, NULL, NULL); +- /* REVISIT should probably take out of shadow region 0 */ +- +- memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(channel), +- &dummy_paramset, PARM_SIZE); +- clear_bit(channel, edma_cc[ctlr]->edma_inuse); +-} +-EXPORT_SYMBOL(edma_free_channel); +- +-/** +- * edma_alloc_slot - allocate DMA parameter RAM +- * @slot: specific slot to allocate; negative for "any unused slot" +- * +- * This allocates a parameter RAM slot, initializing it to hold a +- * dummy transfer. Slots allocated using this routine have not been +- * mapped to a hardware DMA channel, and will normally be used by +- * linking to them from a slot associated with a DMA channel. +- * +- * Normal use is to pass EDMA_SLOT_ANY as the @slot, but specific +- * slots may be allocated on behalf of DSP firmware. +- * +- * Returns the number of the slot, else negative errno. +- */ +-int edma_alloc_slot(unsigned ctlr, int slot) +-{ +- if (slot >= 0) +- slot = EDMA_CHAN_SLOT(slot); +- +- if (slot < 0) { +- slot = edma_cc[ctlr]->num_channels; +- for (;;) { +- slot = find_next_zero_bit(edma_cc[ctlr]->edma_inuse, +- edma_cc[ctlr]->num_slots, slot); +- if (slot == edma_cc[ctlr]->num_slots) +- return -ENOMEM; +- if (!test_and_set_bit(slot, edma_cc[ctlr]->edma_inuse)) +- break; +- } +- } else if (slot < edma_cc[ctlr]->num_channels || +- slot >= edma_cc[ctlr]->num_slots) { +- return -EINVAL; +- } else if (test_and_set_bit(slot, edma_cc[ctlr]->edma_inuse)) { +- return -EBUSY; +- } +- +- memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot), +- &dummy_paramset, PARM_SIZE); +- +- return EDMA_CTLR_CHAN(ctlr, slot); +-} +-EXPORT_SYMBOL(edma_alloc_slot); +- +-/** +- * edma_free_slot - deallocate DMA parameter RAM +- * @slot: parameter RAM slot returned from edma_alloc_slot() +- * +- * This deallocates the parameter RAM slot allocated by edma_alloc_slot(). +- * Callers are responsible for ensuring the slot is inactive, and will +- * not be activated. +- */ +-void edma_free_slot(unsigned slot) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(slot); +- slot = EDMA_CHAN_SLOT(slot); +- +- if (slot < edma_cc[ctlr]->num_channels || +- slot >= edma_cc[ctlr]->num_slots) +- return; +- +- memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot), +- &dummy_paramset, PARM_SIZE); +- clear_bit(slot, edma_cc[ctlr]->edma_inuse); +-} +-EXPORT_SYMBOL(edma_free_slot); +- +- +-/** +- * edma_alloc_cont_slots- alloc contiguous parameter RAM slots +- * The API will return the starting point of a set of +- * contiguous parameter RAM slots that have been requested +- * +- * @id: can only be EDMA_CONT_PARAMS_ANY or EDMA_CONT_PARAMS_FIXED_EXACT +- * or EDMA_CONT_PARAMS_FIXED_NOT_EXACT +- * @count: number of contiguous Paramter RAM slots +- * @slot - the start value of Parameter RAM slot that should be passed if id +- * is EDMA_CONT_PARAMS_FIXED_EXACT or EDMA_CONT_PARAMS_FIXED_NOT_EXACT +- * +- * If id is EDMA_CONT_PARAMS_ANY then the API starts looking for a set of +- * contiguous Parameter RAM slots from parameter RAM 64 in the case of +- * DaVinci SOCs and 32 in the case of DA8xx SOCs. +- * +- * If id is EDMA_CONT_PARAMS_FIXED_EXACT then the API starts looking for a +- * set of contiguous parameter RAM slots from the "slot" that is passed as an +- * argument to the API. +- * +- * If id is EDMA_CONT_PARAMS_FIXED_NOT_EXACT then the API initially tries +- * starts looking for a set of contiguous parameter RAMs from the "slot" +- * that is passed as an argument to the API. On failure the API will try to +- * find a set of contiguous Parameter RAM slots from the remaining Parameter +- * RAM slots +- */ +-int edma_alloc_cont_slots(unsigned ctlr, unsigned int id, int slot, int count) +-{ +- /* +- * The start slot requested should be greater than +- * the number of channels and lesser than the total number +- * of slots +- */ +- if ((id != EDMA_CONT_PARAMS_ANY) && +- (slot < edma_cc[ctlr]->num_channels || +- slot >= edma_cc[ctlr]->num_slots)) +- return -EINVAL; +- +- /* +- * The number of parameter RAM slots requested cannot be less than 1 +- * and cannot be more than the number of slots minus the number of +- * channels +- */ +- if (count < 1 || count > +- (edma_cc[ctlr]->num_slots - edma_cc[ctlr]->num_channels)) +- return -EINVAL; +- +- switch (id) { +- case EDMA_CONT_PARAMS_ANY: +- return reserve_contiguous_slots(ctlr, id, count, +- edma_cc[ctlr]->num_channels); +- case EDMA_CONT_PARAMS_FIXED_EXACT: +- case EDMA_CONT_PARAMS_FIXED_NOT_EXACT: +- return reserve_contiguous_slots(ctlr, id, count, slot); +- default: +- return -EINVAL; +- } +- +-} +-EXPORT_SYMBOL(edma_alloc_cont_slots); +- +-/** +- * edma_free_cont_slots - deallocate DMA parameter RAM slots +- * @slot: first parameter RAM of a set of parameter RAM slots to be freed +- * @count: the number of contiguous parameter RAM slots to be freed +- * +- * This deallocates the parameter RAM slots allocated by +- * edma_alloc_cont_slots. +- * Callers/applications need to keep track of sets of contiguous +- * parameter RAM slots that have been allocated using the edma_alloc_cont_slots +- * API. +- * Callers are responsible for ensuring the slots are inactive, and will +- * not be activated. +- */ +-int edma_free_cont_slots(unsigned slot, int count) +-{ +- unsigned ctlr, slot_to_free; +- int i; +- +- ctlr = EDMA_CTLR(slot); +- slot = EDMA_CHAN_SLOT(slot); +- +- if (slot < edma_cc[ctlr]->num_channels || +- slot >= edma_cc[ctlr]->num_slots || +- count < 1) +- return -EINVAL; +- +- for (i = slot; i < slot + count; ++i) { +- ctlr = EDMA_CTLR(i); +- slot_to_free = EDMA_CHAN_SLOT(i); +- +- memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot_to_free), +- &dummy_paramset, PARM_SIZE); +- clear_bit(slot_to_free, edma_cc[ctlr]->edma_inuse); +- } +- +- return 0; +-} +-EXPORT_SYMBOL(edma_free_cont_slots); +- +-/*-----------------------------------------------------------------------*/ +- +-/* Parameter RAM operations (i) -- read/write partial slots */ +- +-/** +- * edma_set_src - set initial DMA source address in parameter RAM slot +- * @slot: parameter RAM slot being configured +- * @src_port: physical address of source (memory, controller FIFO, etc) +- * @addressMode: INCR, except in very rare cases +- * @fifoWidth: ignored unless @addressMode is FIFO, else specifies the +- * width to use when addressing the fifo (e.g. W8BIT, W32BIT) +- * +- * Note that the source address is modified during the DMA transfer +- * according to edma_set_src_index(). +- */ +-void edma_set_src(unsigned slot, dma_addr_t src_port, +- enum address_mode mode, enum fifo_width width) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(slot); +- slot = EDMA_CHAN_SLOT(slot); +- +- if (slot < edma_cc[ctlr]->num_slots) { +- unsigned int i = edma_parm_read(ctlr, PARM_OPT, slot); +- +- if (mode) { +- /* set SAM and program FWID */ +- i = (i & ~(EDMA_FWID)) | (SAM | ((width & 0x7) << 8)); +- } else { +- /* clear SAM */ +- i &= ~SAM; +- } +- edma_parm_write(ctlr, PARM_OPT, slot, i); +- +- /* set the source port address +- in source register of param structure */ +- edma_parm_write(ctlr, PARM_SRC, slot, src_port); +- } +-} +-EXPORT_SYMBOL(edma_set_src); +- +-/** +- * edma_set_dest - set initial DMA destination address in parameter RAM slot +- * @slot: parameter RAM slot being configured +- * @dest_port: physical address of destination (memory, controller FIFO, etc) +- * @addressMode: INCR, except in very rare cases +- * @fifoWidth: ignored unless @addressMode is FIFO, else specifies the +- * width to use when addressing the fifo (e.g. W8BIT, W32BIT) +- * +- * Note that the destination address is modified during the DMA transfer +- * according to edma_set_dest_index(). +- */ +-void edma_set_dest(unsigned slot, dma_addr_t dest_port, +- enum address_mode mode, enum fifo_width width) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(slot); +- slot = EDMA_CHAN_SLOT(slot); +- +- if (slot < edma_cc[ctlr]->num_slots) { +- unsigned int i = edma_parm_read(ctlr, PARM_OPT, slot); +- +- if (mode) { +- /* set DAM and program FWID */ +- i = (i & ~(EDMA_FWID)) | (DAM | ((width & 0x7) << 8)); +- } else { +- /* clear DAM */ +- i &= ~DAM; +- } +- edma_parm_write(ctlr, PARM_OPT, slot, i); +- /* set the destination port address +- in dest register of param structure */ +- edma_parm_write(ctlr, PARM_DST, slot, dest_port); +- } +-} +-EXPORT_SYMBOL(edma_set_dest); +- +-/** +- * edma_get_position - returns the current transfer points +- * @slot: parameter RAM slot being examined +- * @src: pointer to source port position +- * @dst: pointer to destination port position +- * +- * Returns current source and destination addresses for a particular +- * parameter RAM slot. Its channel should not be active when this is called. +- */ +-void edma_get_position(unsigned slot, dma_addr_t *src, dma_addr_t *dst) +-{ +- struct edmacc_param temp; +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(slot); +- slot = EDMA_CHAN_SLOT(slot); +- +- edma_read_slot(EDMA_CTLR_CHAN(ctlr, slot), &temp); +- if (src != NULL) +- *src = temp.src; +- if (dst != NULL) +- *dst = temp.dst; +-} +-EXPORT_SYMBOL(edma_get_position); +- +-/** +- * edma_set_src_index - configure DMA source address indexing +- * @slot: parameter RAM slot being configured +- * @src_bidx: byte offset between source arrays in a frame +- * @src_cidx: byte offset between source frames in a block +- * +- * Offsets are specified to support either contiguous or discontiguous +- * memory transfers, or repeated access to a hardware register, as needed. +- * When accessing hardware registers, both offsets are normally zero. +- */ +-void edma_set_src_index(unsigned slot, s16 src_bidx, s16 src_cidx) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(slot); +- slot = EDMA_CHAN_SLOT(slot); +- +- if (slot < edma_cc[ctlr]->num_slots) { +- edma_parm_modify(ctlr, PARM_SRC_DST_BIDX, slot, +- 0xffff0000, src_bidx); +- edma_parm_modify(ctlr, PARM_SRC_DST_CIDX, slot, +- 0xffff0000, src_cidx); +- } +-} +-EXPORT_SYMBOL(edma_set_src_index); +- +-/** +- * edma_set_dest_index - configure DMA destination address indexing +- * @slot: parameter RAM slot being configured +- * @dest_bidx: byte offset between destination arrays in a frame +- * @dest_cidx: byte offset between destination frames in a block +- * +- * Offsets are specified to support either contiguous or discontiguous +- * memory transfers, or repeated access to a hardware register, as needed. +- * When accessing hardware registers, both offsets are normally zero. +- */ +-void edma_set_dest_index(unsigned slot, s16 dest_bidx, s16 dest_cidx) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(slot); +- slot = EDMA_CHAN_SLOT(slot); +- +- if (slot < edma_cc[ctlr]->num_slots) { +- edma_parm_modify(ctlr, PARM_SRC_DST_BIDX, slot, +- 0x0000ffff, dest_bidx << 16); +- edma_parm_modify(ctlr, PARM_SRC_DST_CIDX, slot, +- 0x0000ffff, dest_cidx << 16); +- } +-} +-EXPORT_SYMBOL(edma_set_dest_index); +- +-/** +- * edma_set_transfer_params - configure DMA transfer parameters +- * @slot: parameter RAM slot being configured +- * @acnt: how many bytes per array (at least one) +- * @bcnt: how many arrays per frame (at least one) +- * @ccnt: how many frames per block (at least one) +- * @bcnt_rld: used only for A-Synchronized transfers; this specifies +- * the value to reload into bcnt when it decrements to zero +- * @sync_mode: ASYNC or ABSYNC +- * +- * See the EDMA3 documentation to understand how to configure and link +- * transfers using the fields in PaRAM slots. If you are not doing it +- * all at once with edma_write_slot(), you will use this routine +- * plus two calls each for source and destination, setting the initial +- * address and saying how to index that address. +- * +- * An example of an A-Synchronized transfer is a serial link using a +- * single word shift register. In that case, @acnt would be equal to +- * that word size; the serial controller issues a DMA synchronization +- * event to transfer each word, and memory access by the DMA transfer +- * controller will be word-at-a-time. +- * +- * An example of an AB-Synchronized transfer is a device using a FIFO. +- * In that case, @acnt equals the FIFO width and @bcnt equals its depth. +- * The controller with the FIFO issues DMA synchronization events when +- * the FIFO threshold is reached, and the DMA transfer controller will +- * transfer one frame to (or from) the FIFO. It will probably use +- * efficient burst modes to access memory. +- */ +-void edma_set_transfer_params(unsigned slot, +- u16 acnt, u16 bcnt, u16 ccnt, +- u16 bcnt_rld, enum sync_dimension sync_mode) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(slot); +- slot = EDMA_CHAN_SLOT(slot); +- +- if (slot < edma_cc[ctlr]->num_slots) { +- edma_parm_modify(ctlr, PARM_LINK_BCNTRLD, slot, +- 0x0000ffff, bcnt_rld << 16); +- if (sync_mode == ASYNC) +- edma_parm_and(ctlr, PARM_OPT, slot, ~SYNCDIM); +- else +- edma_parm_or(ctlr, PARM_OPT, slot, SYNCDIM); +- /* Set the acount, bcount, ccount registers */ +- edma_parm_write(ctlr, PARM_A_B_CNT, slot, (bcnt << 16) | acnt); +- edma_parm_write(ctlr, PARM_CCNT, slot, ccnt); +- } +-} +-EXPORT_SYMBOL(edma_set_transfer_params); +- +-/** +- * edma_link - link one parameter RAM slot to another +- * @from: parameter RAM slot originating the link +- * @to: parameter RAM slot which is the link target +- * +- * The originating slot should not be part of any active DMA transfer. +- */ +-void edma_link(unsigned from, unsigned to) +-{ +- unsigned ctlr_from, ctlr_to; +- +- ctlr_from = EDMA_CTLR(from); +- from = EDMA_CHAN_SLOT(from); +- ctlr_to = EDMA_CTLR(to); +- to = EDMA_CHAN_SLOT(to); +- +- if (from >= edma_cc[ctlr_from]->num_slots) +- return; +- if (to >= edma_cc[ctlr_to]->num_slots) +- return; +- edma_parm_modify(ctlr_from, PARM_LINK_BCNTRLD, from, 0xffff0000, +- PARM_OFFSET(to)); +-} +-EXPORT_SYMBOL(edma_link); +- +-/** +- * edma_unlink - cut link from one parameter RAM slot +- * @from: parameter RAM slot originating the link +- * +- * The originating slot should not be part of any active DMA transfer. +- * Its link is set to 0xffff. +- */ +-void edma_unlink(unsigned from) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(from); +- from = EDMA_CHAN_SLOT(from); +- +- if (from >= edma_cc[ctlr]->num_slots) +- return; +- edma_parm_or(ctlr, PARM_LINK_BCNTRLD, from, 0xffff); +-} +-EXPORT_SYMBOL(edma_unlink); +- +-/*-----------------------------------------------------------------------*/ +- +-/* Parameter RAM operations (ii) -- read/write whole parameter sets */ +- +-/** +- * edma_write_slot - write parameter RAM data for slot +- * @slot: number of parameter RAM slot being modified +- * @param: data to be written into parameter RAM slot +- * +- * Use this to assign all parameters of a transfer at once. This +- * allows more efficient setup of transfers than issuing multiple +- * calls to set up those parameters in small pieces, and provides +- * complete control over all transfer options. +- */ +-void edma_write_slot(unsigned slot, const struct edmacc_param *param) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(slot); +- slot = EDMA_CHAN_SLOT(slot); +- +- if (slot >= edma_cc[ctlr]->num_slots) +- return; +- memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot), param, +- PARM_SIZE); +-} +-EXPORT_SYMBOL(edma_write_slot); +- +-/** +- * edma_read_slot - read parameter RAM data from slot +- * @slot: number of parameter RAM slot being copied +- * @param: where to store copy of parameter RAM data +- * +- * Use this to read data from a parameter RAM slot, perhaps to +- * save them as a template for later reuse. +- */ +-void edma_read_slot(unsigned slot, struct edmacc_param *param) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(slot); +- slot = EDMA_CHAN_SLOT(slot); +- +- if (slot >= edma_cc[ctlr]->num_slots) +- return; +- memcpy_fromio(param, edmacc_regs_base[ctlr] + PARM_OFFSET(slot), +- PARM_SIZE); +-} +-EXPORT_SYMBOL(edma_read_slot); +- +-/*-----------------------------------------------------------------------*/ +- +-/* Various EDMA channel control operations */ +- +-/** +- * edma_pause - pause dma on a channel +- * @channel: on which edma_start() has been called +- * +- * This temporarily disables EDMA hardware events on the specified channel, +- * preventing them from triggering new transfers on its behalf +- */ +-void edma_pause(unsigned channel) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(channel); +- channel = EDMA_CHAN_SLOT(channel); +- +- if (channel < edma_cc[ctlr]->num_channels) { +- unsigned int mask = BIT(channel & 0x1f); +- +- edma_shadow0_write_array(ctlr, SH_EECR, channel >> 5, mask); +- } +-} +-EXPORT_SYMBOL(edma_pause); +- +-/** +- * edma_resume - resumes dma on a paused channel +- * @channel: on which edma_pause() has been called +- * +- * This re-enables EDMA hardware events on the specified channel. +- */ +-void edma_resume(unsigned channel) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(channel); +- channel = EDMA_CHAN_SLOT(channel); +- +- if (channel < edma_cc[ctlr]->num_channels) { +- unsigned int mask = BIT(channel & 0x1f); +- +- edma_shadow0_write_array(ctlr, SH_EESR, channel >> 5, mask); +- } +-} +-EXPORT_SYMBOL(edma_resume); +- +-/** +- * edma_start - start dma on a channel +- * @channel: channel being activated +- * +- * Channels with event associations will be triggered by their hardware +- * events, and channels without such associations will be triggered by +- * software. (At this writing there is no interface for using software +- * triggers except with channels that don't support hardware triggers.) +- * +- * Returns zero on success, else negative errno. +- */ +-int edma_start(unsigned channel) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(channel); +- channel = EDMA_CHAN_SLOT(channel); +- +- if (channel < edma_cc[ctlr]->num_channels) { +- int j = channel >> 5; +- unsigned int mask = BIT(channel & 0x1f); +- +- /* EDMA channels without event association */ +- if (test_bit(channel, edma_cc[ctlr]->edma_unused)) { +- pr_debug("EDMA: ESR%d %08x\n", j, +- edma_shadow0_read_array(ctlr, SH_ESR, j)); +- edma_shadow0_write_array(ctlr, SH_ESR, j, mask); +- return 0; +- } +- +- /* EDMA channel with event association */ +- pr_debug("EDMA: ER%d %08x\n", j, +- edma_shadow0_read_array(ctlr, SH_ER, j)); +- /* Clear any pending event or error */ +- edma_write_array(ctlr, EDMA_ECR, j, mask); +- edma_write_array(ctlr, EDMA_EMCR, j, mask); +- /* Clear any SER */ +- edma_shadow0_write_array(ctlr, SH_SECR, j, mask); +- edma_shadow0_write_array(ctlr, SH_EESR, j, mask); +- pr_debug("EDMA: EER%d %08x\n", j, +- edma_shadow0_read_array(ctlr, SH_EER, j)); +- return 0; +- } +- +- return -EINVAL; +-} +-EXPORT_SYMBOL(edma_start); +- +-/** +- * edma_stop - stops dma on the channel passed +- * @channel: channel being deactivated +- * +- * When @lch is a channel, any active transfer is paused and +- * all pending hardware events are cleared. The current transfer +- * may not be resumed, and the channel's Parameter RAM should be +- * reinitialized before being reused. +- */ +-void edma_stop(unsigned channel) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(channel); +- channel = EDMA_CHAN_SLOT(channel); +- +- if (channel < edma_cc[ctlr]->num_channels) { +- int j = channel >> 5; +- unsigned int mask = BIT(channel & 0x1f); +- +- edma_shadow0_write_array(ctlr, SH_EECR, j, mask); +- edma_shadow0_write_array(ctlr, SH_ECR, j, mask); +- edma_shadow0_write_array(ctlr, SH_SECR, j, mask); +- edma_write_array(ctlr, EDMA_EMCR, j, mask); +- +- pr_debug("EDMA: EER%d %08x\n", j, +- edma_shadow0_read_array(ctlr, SH_EER, j)); +- +- /* REVISIT: consider guarding against inappropriate event +- * chaining by overwriting with dummy_paramset. +- */ +- } +-} +-EXPORT_SYMBOL(edma_stop); +- +-/****************************************************************************** +- * +- * It cleans ParamEntry qand bring back EDMA to initial state if media has +- * been removed before EDMA has finished.It is usedful for removable media. +- * Arguments: +- * ch_no - channel no +- * +- * Return: zero on success, or corresponding error no on failure +- * +- * FIXME this should not be needed ... edma_stop() should suffice. +- * +- *****************************************************************************/ +- +-void edma_clean_channel(unsigned channel) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(channel); +- channel = EDMA_CHAN_SLOT(channel); +- +- if (channel < edma_cc[ctlr]->num_channels) { +- int j = (channel >> 5); +- unsigned int mask = BIT(channel & 0x1f); +- +- pr_debug("EDMA: EMR%d %08x\n", j, +- edma_read_array(ctlr, EDMA_EMR, j)); +- edma_shadow0_write_array(ctlr, SH_ECR, j, mask); +- /* Clear the corresponding EMR bits */ +- edma_write_array(ctlr, EDMA_EMCR, j, mask); +- /* Clear any SER */ +- edma_shadow0_write_array(ctlr, SH_SECR, j, mask); +- edma_write(ctlr, EDMA_CCERRCLR, BIT(16) | BIT(1) | BIT(0)); +- } +-} +-EXPORT_SYMBOL(edma_clean_channel); +- +-/* +- * edma_clear_event - clear an outstanding event on the DMA channel +- * Arguments: +- * channel - channel number +- */ +-void edma_clear_event(unsigned channel) +-{ +- unsigned ctlr; +- +- ctlr = EDMA_CTLR(channel); +- channel = EDMA_CHAN_SLOT(channel); +- +- if (channel >= edma_cc[ctlr]->num_channels) +- return; +- if (channel < 32) +- edma_write(ctlr, EDMA_ECR, BIT(channel)); +- else +- edma_write(ctlr, EDMA_ECRH, BIT(channel - 32)); +-} +-EXPORT_SYMBOL(edma_clear_event); +- +-/*-----------------------------------------------------------------------*/ +- +-static int __init edma_probe(struct platform_device *pdev) +-{ +- struct edma_soc_info **info = pdev->dev.platform_data; +- const s8 (*queue_priority_mapping)[2]; +- const s8 (*queue_tc_mapping)[2]; +- int i, j, off, ln, found = 0; +- int status = -1; +- const s16 (*rsv_chans)[2]; +- const s16 (*rsv_slots)[2]; +- int irq[EDMA_MAX_CC] = {0, 0}; +- int err_irq[EDMA_MAX_CC] = {0, 0}; +- struct resource *r[EDMA_MAX_CC] = {NULL}; +- resource_size_t len[EDMA_MAX_CC]; +- char res_name[10]; +- char irq_name[10]; +- +- if (!info) +- return -ENODEV; +- +- for (j = 0; j < EDMA_MAX_CC; j++) { +- sprintf(res_name, "edma_cc%d", j); +- r[j] = platform_get_resource_byname(pdev, IORESOURCE_MEM, +- res_name); +- if (!r[j] || !info[j]) { +- if (found) +- break; +- else +- return -ENODEV; +- } else { +- found = 1; +- } +- +- len[j] = resource_size(r[j]); +- +- r[j] = request_mem_region(r[j]->start, len[j], +- dev_name(&pdev->dev)); +- if (!r[j]) { +- status = -EBUSY; +- goto fail1; +- } +- +- edmacc_regs_base[j] = ioremap(r[j]->start, len[j]); +- if (!edmacc_regs_base[j]) { +- status = -EBUSY; +- goto fail1; +- } +- +- edma_cc[j] = kzalloc(sizeof(struct edma), GFP_KERNEL); +- if (!edma_cc[j]) { +- status = -ENOMEM; +- goto fail1; +- } +- +- edma_cc[j]->num_channels = min_t(unsigned, info[j]->n_channel, +- EDMA_MAX_DMACH); +- edma_cc[j]->num_slots = min_t(unsigned, info[j]->n_slot, +- EDMA_MAX_PARAMENTRY); +- edma_cc[j]->num_cc = min_t(unsigned, info[j]->n_cc, +- EDMA_MAX_CC); +- +- edma_cc[j]->default_queue = info[j]->default_queue; +- +- dev_dbg(&pdev->dev, "DMA REG BASE ADDR=%p\n", +- edmacc_regs_base[j]); +- +- for (i = 0; i < edma_cc[j]->num_slots; i++) +- memcpy_toio(edmacc_regs_base[j] + PARM_OFFSET(i), +- &dummy_paramset, PARM_SIZE); +- +- /* Mark all channels as unused */ +- memset(edma_cc[j]->edma_unused, 0xff, +- sizeof(edma_cc[j]->edma_unused)); +- +- if (info[j]->rsv) { +- +- /* Clear the reserved channels in unused list */ +- rsv_chans = info[j]->rsv->rsv_chans; +- if (rsv_chans) { +- for (i = 0; rsv_chans[i][0] != -1; i++) { +- off = rsv_chans[i][0]; +- ln = rsv_chans[i][1]; +- clear_bits(off, ln, +- edma_cc[j]->edma_unused); +- } +- } +- +- /* Set the reserved slots in inuse list */ +- rsv_slots = info[j]->rsv->rsv_slots; +- if (rsv_slots) { +- for (i = 0; rsv_slots[i][0] != -1; i++) { +- off = rsv_slots[i][0]; +- ln = rsv_slots[i][1]; +- set_bits(off, ln, +- edma_cc[j]->edma_inuse); +- } +- } +- } +- +- sprintf(irq_name, "edma%d", j); +- irq[j] = platform_get_irq_byname(pdev, irq_name); +- edma_cc[j]->irq_res_start = irq[j]; +- status = request_irq(irq[j], dma_irq_handler, 0, "edma", +- &pdev->dev); +- if (status < 0) { +- dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n", +- irq[j], status); +- goto fail; +- } +- +- sprintf(irq_name, "edma%d_err", j); +- err_irq[j] = platform_get_irq_byname(pdev, irq_name); +- edma_cc[j]->irq_res_end = err_irq[j]; +- status = request_irq(err_irq[j], dma_ccerr_handler, 0, +- "edma_error", &pdev->dev); +- if (status < 0) { +- dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n", +- err_irq[j], status); +- goto fail; +- } +- +- for (i = 0; i < edma_cc[j]->num_channels; i++) +- map_dmach_queue(j, i, info[j]->default_queue); +- +- queue_tc_mapping = info[j]->queue_tc_mapping; +- queue_priority_mapping = info[j]->queue_priority_mapping; +- +- /* Event queue to TC mapping */ +- for (i = 0; queue_tc_mapping[i][0] != -1; i++) +- map_queue_tc(j, queue_tc_mapping[i][0], +- queue_tc_mapping[i][1]); +- +- /* Event queue priority mapping */ +- for (i = 0; queue_priority_mapping[i][0] != -1; i++) +- assign_priority_to_queue(j, +- queue_priority_mapping[i][0], +- queue_priority_mapping[i][1]); +- +- /* Map the channel to param entry if channel mapping logic +- * exist +- */ +- if (edma_read(j, EDMA_CCCFG) & CHMAP_EXIST) +- map_dmach_param(j); +- +- for (i = 0; i < info[j]->n_region; i++) { +- edma_write_array2(j, EDMA_DRAE, i, 0, 0x0); +- edma_write_array2(j, EDMA_DRAE, i, 1, 0x0); +- edma_write_array(j, EDMA_QRAE, i, 0x0); +- } +- arch_num_cc++; +- } +- +- if (tc_errs_handled) { +- status = request_irq(IRQ_TCERRINT0, dma_tc0err_handler, 0, +- "edma_tc0", &pdev->dev); +- if (status < 0) { +- dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n", +- IRQ_TCERRINT0, status); +- return status; +- } +- status = request_irq(IRQ_TCERRINT, dma_tc1err_handler, 0, +- "edma_tc1", &pdev->dev); +- if (status < 0) { +- dev_dbg(&pdev->dev, "request_irq %d --> %d\n", +- IRQ_TCERRINT, status); +- return status; +- } +- } +- +- return 0; +- +-fail: +- for (i = 0; i < EDMA_MAX_CC; i++) { +- if (err_irq[i]) +- free_irq(err_irq[i], &pdev->dev); +- if (irq[i]) +- free_irq(irq[i], &pdev->dev); +- } +-fail1: +- for (i = 0; i < EDMA_MAX_CC; i++) { +- if (r[i]) +- release_mem_region(r[i]->start, len[i]); +- if (edmacc_regs_base[i]) +- iounmap(edmacc_regs_base[i]); +- kfree(edma_cc[i]); +- } +- return status; +-} +- +- +-static struct platform_driver edma_driver = { +- .driver.name = "edma", +-}; +- +-static int __init edma_init(void) +-{ +- return platform_driver_probe(&edma_driver, edma_probe); +-} +-arch_initcall(edma_init); +- +diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h +index aaccdc4..4380691 100644 +--- a/arch/arm/mach-davinci/include/mach/da8xx.h ++++ b/arch/arm/mach-davinci/include/mach/da8xx.h +@@ -20,8 +20,8 @@ + #include <linux/videodev2.h> + + #include <mach/serial.h> +-#include <mach/edma.h> + #include <mach/pm.h> ++#include <linux/platform_data/edma.h> + #include <linux/platform_data/i2c-davinci.h> + #include <linux/platform_data/mmc-davinci.h> + #include <linux/platform_data/usb-davinci.h> +diff --git a/arch/arm/mach-davinci/include/mach/edma.h b/arch/arm/mach-davinci/include/mach/edma.h +deleted file mode 100644 +index 7e84c90..0000000 +--- a/arch/arm/mach-davinci/include/mach/edma.h ++++ /dev/null +@@ -1,267 +0,0 @@ +-/* +- * TI DAVINCI dma definitions +- * +- * Copyright (C) 2006-2009 Texas Instruments. +- * +- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- * +- * 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. +- * +- */ +- +-/* +- * This EDMA3 programming framework exposes two basic kinds of resource: +- * +- * Channel Triggers transfers, usually from a hardware event but +- * also manually or by "chaining" from DMA completions. +- * Each channel is coupled to a Parameter RAM (PaRAM) slot. +- * +- * Slot Each PaRAM slot holds a DMA transfer descriptor (PaRAM +- * "set"), source and destination addresses, a link to a +- * next PaRAM slot (if any), options for the transfer, and +- * instructions for updating those addresses. There are +- * more than twice as many slots as event channels. +- * +- * Each PaRAM set describes a sequence of transfers, either for one large +- * buffer or for several discontiguous smaller buffers. An EDMA transfer +- * is driven only from a channel, which performs the transfers specified +- * in its PaRAM slot until there are no more transfers. When that last +- * transfer completes, the "link" field may be used to reload the channel's +- * PaRAM slot with a new transfer descriptor. +- * +- * The EDMA Channel Controller (CC) maps requests from channels into physical +- * Transfer Controller (TC) requests when the channel triggers (by hardware +- * or software events, or by chaining). The two physical DMA channels provided +- * by the TCs are thus shared by many logical channels. +- * +- * DaVinci hardware also has a "QDMA" mechanism which is not currently +- * supported through this interface. (DSP firmware uses it though.) +- */ +- +-#ifndef EDMA_H_ +-#define EDMA_H_ +- +-/* PaRAM slots are laid out like this */ +-struct edmacc_param { +- unsigned int opt; +- unsigned int src; +- unsigned int a_b_cnt; +- unsigned int dst; +- unsigned int src_dst_bidx; +- unsigned int link_bcntrld; +- unsigned int src_dst_cidx; +- unsigned int ccnt; +-}; +- +-#define CCINT0_INTERRUPT 16 +-#define CCERRINT_INTERRUPT 17 +-#define TCERRINT0_INTERRUPT 18 +-#define TCERRINT1_INTERRUPT 19 +- +-/* fields in edmacc_param.opt */ +-#define SAM BIT(0) +-#define DAM BIT(1) +-#define SYNCDIM BIT(2) +-#define STATIC BIT(3) +-#define EDMA_FWID (0x07 << 8) +-#define TCCMODE BIT(11) +-#define EDMA_TCC(t) ((t) << 12) +-#define TCINTEN BIT(20) +-#define ITCINTEN BIT(21) +-#define TCCHEN BIT(22) +-#define ITCCHEN BIT(23) +- +-#define TRWORD (0x7<<2) +-#define PAENTRY (0x1ff<<5) +- +-/* Drivers should avoid using these symbolic names for dm644x +- * channels, and use platform_device IORESOURCE_DMA resources +- * instead. (Other DaVinci chips have different peripherals +- * and thus have different DMA channel mappings.) +- */ +-#define DAVINCI_DMA_MCBSP_TX 2 +-#define DAVINCI_DMA_MCBSP_RX 3 +-#define DAVINCI_DMA_VPSS_HIST 4 +-#define DAVINCI_DMA_VPSS_H3A 5 +-#define DAVINCI_DMA_VPSS_PRVU 6 +-#define DAVINCI_DMA_VPSS_RSZ 7 +-#define DAVINCI_DMA_IMCOP_IMXINT 8 +-#define DAVINCI_DMA_IMCOP_VLCDINT 9 +-#define DAVINCI_DMA_IMCO_PASQINT 10 +-#define DAVINCI_DMA_IMCOP_DSQINT 11 +-#define DAVINCI_DMA_SPI_SPIX 16 +-#define DAVINCI_DMA_SPI_SPIR 17 +-#define DAVINCI_DMA_UART0_URXEVT0 18 +-#define DAVINCI_DMA_UART0_UTXEVT0 19 +-#define DAVINCI_DMA_UART1_URXEVT1 20 +-#define DAVINCI_DMA_UART1_UTXEVT1 21 +-#define DAVINCI_DMA_UART2_URXEVT2 22 +-#define DAVINCI_DMA_UART2_UTXEVT2 23 +-#define DAVINCI_DMA_MEMSTK_MSEVT 24 +-#define DAVINCI_DMA_MMCRXEVT 26 +-#define DAVINCI_DMA_MMCTXEVT 27 +-#define DAVINCI_DMA_I2C_ICREVT 28 +-#define DAVINCI_DMA_I2C_ICXEVT 29 +-#define DAVINCI_DMA_GPIO_GPINT0 32 +-#define DAVINCI_DMA_GPIO_GPINT1 33 +-#define DAVINCI_DMA_GPIO_GPINT2 34 +-#define DAVINCI_DMA_GPIO_GPINT3 35 +-#define DAVINCI_DMA_GPIO_GPINT4 36 +-#define DAVINCI_DMA_GPIO_GPINT5 37 +-#define DAVINCI_DMA_GPIO_GPINT6 38 +-#define DAVINCI_DMA_GPIO_GPINT7 39 +-#define DAVINCI_DMA_GPIO_GPBNKINT0 40 +-#define DAVINCI_DMA_GPIO_GPBNKINT1 41 +-#define DAVINCI_DMA_GPIO_GPBNKINT2 42 +-#define DAVINCI_DMA_GPIO_GPBNKINT3 43 +-#define DAVINCI_DMA_GPIO_GPBNKINT4 44 +-#define DAVINCI_DMA_TIMER0_TINT0 48 +-#define DAVINCI_DMA_TIMER1_TINT1 49 +-#define DAVINCI_DMA_TIMER2_TINT2 50 +-#define DAVINCI_DMA_TIMER3_TINT3 51 +-#define DAVINCI_DMA_PWM0 52 +-#define DAVINCI_DMA_PWM1 53 +-#define DAVINCI_DMA_PWM2 54 +- +-/* DA830 specific EDMA3 information */ +-#define EDMA_DA830_NUM_DMACH 32 +-#define EDMA_DA830_NUM_TCC 32 +-#define EDMA_DA830_NUM_PARAMENTRY 128 +-#define EDMA_DA830_NUM_EVQUE 2 +-#define EDMA_DA830_NUM_TC 2 +-#define EDMA_DA830_CHMAP_EXIST 0 +-#define EDMA_DA830_NUM_REGIONS 4 +-#define DA830_DMACH2EVENT_MAP0 0x000FC03Fu +-#define DA830_DMACH2EVENT_MAP1 0x00000000u +-#define DA830_EDMA_ARM_OWN 0x30FFCCFFu +- +-/*ch_status paramater of callback function possible values*/ +-#define DMA_COMPLETE 1 +-#define DMA_CC_ERROR 2 +-#define DMA_TC1_ERROR 3 +-#define DMA_TC2_ERROR 4 +- +-enum address_mode { +- INCR = 0, +- FIFO = 1 +-}; +- +-enum fifo_width { +- W8BIT = 0, +- W16BIT = 1, +- W32BIT = 2, +- W64BIT = 3, +- W128BIT = 4, +- W256BIT = 5 +-}; +- +-enum dma_event_q { +- EVENTQ_0 = 0, +- EVENTQ_1 = 1, +- EVENTQ_2 = 2, +- EVENTQ_3 = 3, +- EVENTQ_DEFAULT = -1 +-}; +- +-enum sync_dimension { +- ASYNC = 0, +- ABSYNC = 1 +-}; +- +-#define EDMA_CTLR_CHAN(ctlr, chan) (((ctlr) << 16) | (chan)) +-#define EDMA_CTLR(i) ((i) >> 16) +-#define EDMA_CHAN_SLOT(i) ((i) & 0xffff) +- +-#define EDMA_CHANNEL_ANY -1 /* for edma_alloc_channel() */ +-#define EDMA_SLOT_ANY -1 /* for edma_alloc_slot() */ +-#define EDMA_CONT_PARAMS_ANY 1001 +-#define EDMA_CONT_PARAMS_FIXED_EXACT 1002 +-#define EDMA_CONT_PARAMS_FIXED_NOT_EXACT 1003 +- +-#define EDMA_MAX_CC 2 +- +-/* alloc/free DMA channels and their dedicated parameter RAM slots */ +-int edma_alloc_channel(int channel, +- void (*callback)(unsigned channel, u16 ch_status, void *data), +- void *data, enum dma_event_q); +-void edma_free_channel(unsigned channel); +- +-/* alloc/free parameter RAM slots */ +-int edma_alloc_slot(unsigned ctlr, int slot); +-void edma_free_slot(unsigned slot); +- +-/* alloc/free a set of contiguous parameter RAM slots */ +-int edma_alloc_cont_slots(unsigned ctlr, unsigned int id, int slot, int count); +-int edma_free_cont_slots(unsigned slot, int count); +- +-/* calls that operate on part of a parameter RAM slot */ +-void edma_set_src(unsigned slot, dma_addr_t src_port, +- enum address_mode mode, enum fifo_width); +-void edma_set_dest(unsigned slot, dma_addr_t dest_port, +- enum address_mode mode, enum fifo_width); +-void edma_get_position(unsigned slot, dma_addr_t *src, dma_addr_t *dst); +-void edma_set_src_index(unsigned slot, s16 src_bidx, s16 src_cidx); +-void edma_set_dest_index(unsigned slot, s16 dest_bidx, s16 dest_cidx); +-void edma_set_transfer_params(unsigned slot, u16 acnt, u16 bcnt, u16 ccnt, +- u16 bcnt_rld, enum sync_dimension sync_mode); +-void edma_link(unsigned from, unsigned to); +-void edma_unlink(unsigned from); +- +-/* calls that operate on an entire parameter RAM slot */ +-void edma_write_slot(unsigned slot, const struct edmacc_param *params); +-void edma_read_slot(unsigned slot, struct edmacc_param *params); +- +-/* channel control operations */ +-int edma_start(unsigned channel); +-void edma_stop(unsigned channel); +-void edma_clean_channel(unsigned channel); +-void edma_clear_event(unsigned channel); +-void edma_pause(unsigned channel); +-void edma_resume(unsigned channel); +- +-struct edma_rsv_info { +- +- const s16 (*rsv_chans)[2]; +- const s16 (*rsv_slots)[2]; +-}; +- +-/* platform_data for EDMA driver */ +-struct edma_soc_info { +- +- /* how many dma resources of each type */ +- unsigned n_channel; +- unsigned n_region; +- unsigned n_slot; +- unsigned n_tc; +- unsigned n_cc; +- /* +- * Default queue is expected to be a low-priority queue. +- * This way, long transfers on the default queue started +- * by the codec engine will not cause audio defects. +- */ +- enum dma_event_q default_queue; +- +- /* Resource reservation for other cores */ +- struct edma_rsv_info *rsv; +- +- const s8 (*queue_tc_mapping)[2]; +- const s8 (*queue_priority_mapping)[2]; +-}; +- +-#endif +diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig +index 82fcb20..74ce024 100644 +--- a/arch/arm/plat-omap/Kconfig ++++ b/arch/arm/plat-omap/Kconfig +@@ -29,6 +29,7 @@ config ARCH_OMAP2PLUS + select PINCTRL + select PROC_DEVICETREE if PROC_FS + select SPARSE_IRQ ++ select TI_PRIV_EDMA + select USE_OF + help + "Systems based on OMAP2, OMAP3, OMAP4 or OMAP5" +diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c +index fdcf079..47ba7bf 100644 +--- a/drivers/dma/edma.c ++++ b/drivers/dma/edma.c +@@ -24,7 +24,7 @@ + #include <linux/slab.h> + #include <linux/spinlock.h> + +-#include <mach/edma.h> ++#include <linux/platform_data/edma.h> + + #include "dmaengine.h" + #include "virt-dma.h" +diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c +index 2063677..f5d46ea 100644 +--- a/drivers/mmc/host/davinci_mmc.c ++++ b/drivers/mmc/host/davinci_mmc.c +@@ -35,6 +35,7 @@ + #include <linux/edma.h> + #include <linux/mmc/mmc.h> + ++#include <linux/platform_data/edma.h> + #include <linux/platform_data/mmc-davinci.h> + + /* +diff --git a/include/linux/mfd/davinci_voicecodec.h b/include/linux/mfd/davinci_voicecodec.h +index 0ab6132..7dd6524 100644 +--- a/include/linux/mfd/davinci_voicecodec.h ++++ b/include/linux/mfd/davinci_voicecodec.h +@@ -26,8 +26,7 @@ + #include <linux/kernel.h> + #include <linux/platform_device.h> + #include <linux/mfd/core.h> +- +-#include <mach/edma.h> ++#include <linux/platform_data/edma.h> + + /* + * Register values. +diff --git a/include/linux/platform_data/edma.h b/include/linux/platform_data/edma.h +new file mode 100644 +index 0000000..7396f0b3 +--- /dev/null ++++ b/include/linux/platform_data/edma.h +@@ -0,0 +1,198 @@ ++/* ++ * TI DAVINCI dma definitions ++ * ++ * Copyright (C) 2006-2009 Texas Instruments. ++ * ++ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN ++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * 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. ++ * ++ */ ++ ++/* ++ * This EDMA3 programming framework exposes two basic kinds of resource: ++ * ++ * Channel Triggers transfers, usually from a hardware event but ++ * also manually or by "chaining" from DMA completions. ++ * Each channel is coupled to a Parameter RAM (PaRAM) slot. ++ * ++ * Slot Each PaRAM slot holds a DMA transfer descriptor (PaRAM ++ * "set"), source and destination addresses, a link to a ++ * next PaRAM slot (if any), options for the transfer, and ++ * instructions for updating those addresses. There are ++ * more than twice as many slots as event channels. ++ * ++ * Each PaRAM set describes a sequence of transfers, either for one large ++ * buffer or for several discontiguous smaller buffers. An EDMA transfer ++ * is driven only from a channel, which performs the transfers specified ++ * in its PaRAM slot until there are no more transfers. When that last ++ * transfer completes, the "link" field may be used to reload the channel's ++ * PaRAM slot with a new transfer descriptor. ++ * ++ * The EDMA Channel Controller (CC) maps requests from channels into physical ++ * Transfer Controller (TC) requests when the channel triggers (by hardware ++ * or software events, or by chaining). The two physical DMA channels provided ++ * by the TCs are thus shared by many logical channels. ++ * ++ * DaVinci hardware also has a "QDMA" mechanism which is not currently ++ * supported through this interface. (DSP firmware uses it though.) ++ */ ++ ++#ifndef EDMA_H_ ++#define EDMA_H_ ++ ++/* PaRAM slots are laid out like this */ ++struct edmacc_param { ++ unsigned int opt; ++ unsigned int src; ++ unsigned int a_b_cnt; ++ unsigned int dst; ++ unsigned int src_dst_bidx; ++ unsigned int link_bcntrld; ++ unsigned int src_dst_cidx; ++ unsigned int ccnt; ++}; ++ ++/* fields in edmacc_param.opt */ ++#define SAM BIT(0) ++#define DAM BIT(1) ++#define SYNCDIM BIT(2) ++#define STATIC BIT(3) ++#define EDMA_FWID (0x07 << 8) ++#define TCCMODE BIT(11) ++#define EDMA_TCC(t) ((t) << 12) ++#define TCINTEN BIT(20) ++#define ITCINTEN BIT(21) ++#define TCCHEN BIT(22) ++#define ITCCHEN BIT(23) ++ ++/*ch_status paramater of callback function possible values*/ ++#define DMA_COMPLETE 1 ++#define DMA_CC_ERROR 2 ++#define DMA_TC1_ERROR 3 ++#define DMA_TC2_ERROR 4 ++ ++enum address_mode { ++ INCR = 0, ++ FIFO = 1 ++}; ++ ++enum fifo_width { ++ W8BIT = 0, ++ W16BIT = 1, ++ W32BIT = 2, ++ W64BIT = 3, ++ W128BIT = 4, ++ W256BIT = 5 ++}; ++ ++enum dma_event_q { ++ EVENTQ_0 = 0, ++ EVENTQ_1 = 1, ++ EVENTQ_2 = 2, ++ EVENTQ_3 = 3, ++ EVENTQ_DEFAULT = -1 ++}; ++ ++enum sync_dimension { ++ ASYNC = 0, ++ ABSYNC = 1 ++}; ++ ++#define EDMA_CTLR_CHAN(ctlr, chan) (((ctlr) << 16) | (chan)) ++#define EDMA_CTLR(i) ((i) >> 16) ++#define EDMA_CHAN_SLOT(i) ((i) & 0xffff) ++ ++#define EDMA_CHANNEL_ANY -1 /* for edma_alloc_channel() */ ++#define EDMA_SLOT_ANY -1 /* for edma_alloc_slot() */ ++#define EDMA_CONT_PARAMS_ANY 1001 ++#define EDMA_CONT_PARAMS_FIXED_EXACT 1002 ++#define EDMA_CONT_PARAMS_FIXED_NOT_EXACT 1003 ++ ++#define EDMA_MAX_CC 2 ++ ++/* alloc/free DMA channels and their dedicated parameter RAM slots */ ++int edma_alloc_channel(int channel, ++ void (*callback)(unsigned channel, u16 ch_status, void *data), ++ void *data, enum dma_event_q); ++void edma_free_channel(unsigned channel); ++ ++/* alloc/free parameter RAM slots */ ++int edma_alloc_slot(unsigned ctlr, int slot); ++void edma_free_slot(unsigned slot); ++ ++/* alloc/free a set of contiguous parameter RAM slots */ ++int edma_alloc_cont_slots(unsigned ctlr, unsigned int id, int slot, int count); ++int edma_free_cont_slots(unsigned slot, int count); ++ ++/* calls that operate on part of a parameter RAM slot */ ++void edma_set_src(unsigned slot, dma_addr_t src_port, ++ enum address_mode mode, enum fifo_width); ++void edma_set_dest(unsigned slot, dma_addr_t dest_port, ++ enum address_mode mode, enum fifo_width); ++void edma_get_position(unsigned slot, dma_addr_t *src, dma_addr_t *dst); ++void edma_set_src_index(unsigned slot, s16 src_bidx, s16 src_cidx); ++void edma_set_dest_index(unsigned slot, s16 dest_bidx, s16 dest_cidx); ++void edma_set_transfer_params(unsigned slot, u16 acnt, u16 bcnt, u16 ccnt, ++ u16 bcnt_rld, enum sync_dimension sync_mode); ++void edma_link(unsigned from, unsigned to); ++void edma_unlink(unsigned from); ++ ++/* calls that operate on an entire parameter RAM slot */ ++void edma_write_slot(unsigned slot, const struct edmacc_param *params); ++void edma_read_slot(unsigned slot, struct edmacc_param *params); ++ ++/* channel control operations */ ++int edma_start(unsigned channel); ++void edma_stop(unsigned channel); ++void edma_clean_channel(unsigned channel); ++void edma_clear_event(unsigned channel); ++void edma_pause(unsigned channel); ++void edma_resume(unsigned channel); ++ ++struct edma_rsv_info { ++ ++ const s16 (*rsv_chans)[2]; ++ const s16 (*rsv_slots)[2]; ++}; ++ ++/* platform_data for EDMA driver */ ++struct edma_soc_info { ++ ++ /* how many dma resources of each type */ ++ unsigned n_channel; ++ unsigned n_region; ++ unsigned n_slot; ++ unsigned n_tc; ++ unsigned n_cc; ++ /* ++ * Default queue is expected to be a low-priority queue. ++ * This way, long transfers on the default queue started ++ * by the codec engine will not cause audio defects. ++ */ ++ enum dma_event_q default_queue; ++ ++ /* Resource reservation for other cores */ ++ struct edma_rsv_info *rsv; ++ ++ const s8 (*queue_tc_mapping)[2]; ++ const s8 (*queue_priority_mapping)[2]; ++}; ++ ++#endif +diff --git a/include/linux/platform_data/spi-davinci.h b/include/linux/platform_data/spi-davinci.h +index 7af305b..8dc2fa47 100644 +--- a/include/linux/platform_data/spi-davinci.h ++++ b/include/linux/platform_data/spi-davinci.h +@@ -19,7 +19,7 @@ + #ifndef __ARCH_ARM_DAVINCI_SPI_H + #define __ARCH_ARM_DAVINCI_SPI_H + +-#include <mach/edma.h> ++#include <linux/platform_data/edma.h> + + #define SPI_INTERN_CS 0xFF + +diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c +index 6fac5af..44365d5 100644 +--- a/sound/soc/davinci/davinci-evm.c ++++ b/sound/soc/davinci/davinci-evm.c +@@ -14,6 +14,7 @@ + #include <linux/timer.h> + #include <linux/interrupt.h> + #include <linux/platform_device.h> ++#include <linux/platform_data/edma.h> + #include <linux/i2c.h> + #include <sound/core.h> + #include <sound/pcm.h> +diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c +index 93ea3bf..c9d1b7a 100644 +--- a/sound/soc/davinci/davinci-pcm.c ++++ b/sound/soc/davinci/davinci-pcm.c +@@ -16,6 +16,7 @@ + #include <linux/slab.h> + #include <linux/dma-mapping.h> + #include <linux/kernel.h> ++#include <linux/platform_data/edma.h> + + #include <sound/core.h> + #include <sound/pcm.h> +diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h +index fc4d01c..deab6c3 100644 +--- a/sound/soc/davinci/davinci-pcm.h ++++ b/sound/soc/davinci/davinci-pcm.h +@@ -13,7 +13,7 @@ + #define _DAVINCI_PCM_H + + #include <linux/platform_data/davinci_asp.h> +-#include <mach/edma.h> ++#include <linux/platform_data/edma.h> + + struct davinci_pcm_dma_params { + int channel; /* sync dma channel ID */ +diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c +index 5be65aa..5345e63 100644 +--- a/sound/soc/davinci/davinci-sffsdr.c ++++ b/sound/soc/davinci/davinci-sffsdr.c +@@ -17,6 +17,7 @@ + #include <linux/timer.h> + #include <linux/interrupt.h> + #include <linux/platform_device.h> ++#include <linux/platform_data/edma.h> + #include <linux/gpio.h> + #include <sound/core.h> + #include <sound/pcm.h> +@@ -28,7 +29,6 @@ + #include <asm/plat-sffsdr/sffsdr-fpga.h> + #endif + +-#include <mach/edma.h> + + #include "../codecs/pcm3008.h" + #include "davinci-pcm.h" +@@ -123,8 +123,8 @@ static struct resource sffsdr_snd_resources[] = { + }; + + static struct evm_snd_platform_data sffsdr_snd_data = { +- .tx_dma_ch = DAVINCI_DMA_MCBSP_TX, +- .rx_dma_ch = DAVINCI_DMA_MCBSP_RX, ++ .tx_dma_ch = 2, ++ .rx_dma_ch = 3, + }; + + static struct platform_device *sffsdr_snd_device; diff --git a/patches/linux-3.7-rc6/0010-ARM-edma-remove-unused-transfer-controller-handlers.patch b/patches/linux-3.7-rc6/0010-ARM-edma-remove-unused-transfer-controller-handlers.patch new file mode 100644 index 0000000..f05c02a --- /dev/null +++ b/patches/linux-3.7-rc6/0010-ARM-edma-remove-unused-transfer-controller-handlers.patch @@ -0,0 +1,69 @@ +From 9b14772219c6edaf900645ad688abf8591f6c6a7 Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Wed, 22 Aug 2012 09:31:49 -0400 +Subject: [PATCH] ARM: edma: remove unused transfer controller handlers + +Fix build on OMAP, the irqs are undefined on AM33xx. +These error interrupt handlers were hardcoded as disabled +so since they are unused code, simply remove them. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + arch/arm/common/edma.c | 37 ------------------------------------- + 1 file changed, 37 deletions(-) + +diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c +index 4411087..a3d189d 100644 +--- a/arch/arm/common/edma.c ++++ b/arch/arm/common/edma.c +@@ -494,26 +494,6 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data) + return IRQ_HANDLED; + } + +-/****************************************************************************** +- * +- * Transfer controller error interrupt handlers +- * +- *****************************************************************************/ +- +-#define tc_errs_handled false /* disabled as long as they're NOPs */ +- +-static irqreturn_t dma_tc0err_handler(int irq, void *data) +-{ +- dev_dbg(data, "dma_tc0err_handler\n"); +- return IRQ_HANDLED; +-} +- +-static irqreturn_t dma_tc1err_handler(int irq, void *data) +-{ +- dev_dbg(data, "dma_tc1err_handler\n"); +- return IRQ_HANDLED; +-} +- + static int reserve_contiguous_slots(int ctlr, unsigned int id, + unsigned int num_slots, + unsigned int start_slot) +@@ -1538,23 +1518,6 @@ static int __init edma_probe(struct platform_device *pdev) + arch_num_cc++; + } + +- if (tc_errs_handled) { +- status = request_irq(IRQ_TCERRINT0, dma_tc0err_handler, 0, +- "edma_tc0", &pdev->dev); +- if (status < 0) { +- dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n", +- IRQ_TCERRINT0, status); +- return status; +- } +- status = request_irq(IRQ_TCERRINT, dma_tc1err_handler, 0, +- "edma_tc1", &pdev->dev); +- if (status < 0) { +- dev_dbg(&pdev->dev, "request_irq %d --> %d\n", +- IRQ_TCERRINT, status); +- return status; +- } +- } +- + return 0; + + fail: diff --git a/patches/linux-3.7-rc6/0011-ARM-edma-add-DT-and-runtime-PM-support-for-AM33XX.patch b/patches/linux-3.7-rc6/0011-ARM-edma-add-DT-and-runtime-PM-support-for-AM33XX.patch new file mode 100644 index 0000000..e197daf --- /dev/null +++ b/patches/linux-3.7-rc6/0011-ARM-edma-add-DT-and-runtime-PM-support-for-AM33XX.patch @@ -0,0 +1,633 @@ +From 98622c01c7b234d869066035776c906feff18a53 Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Thu, 6 Sep 2012 17:40:42 -0400 +Subject: [PATCH] ARM: edma: add DT and runtime PM support for AM33XX + +Adds support for parsing the TI EDMA DT data into the required +EDMA private API platform data. + +Calls runtime PM API only in the DT case in order to unidle the +associated hwmods on AM33XX. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + arch/arm/common/edma.c | 255 +++++++++++++++++++++++++-- + arch/arm/mach-davinci/board-da830-evm.c | 4 +- + arch/arm/mach-davinci/board-da850-evm.c | 8 +- + arch/arm/mach-davinci/board-dm646x-evm.c | 4 +- + arch/arm/mach-davinci/board-omapl138-hawk.c | 8 +- + arch/arm/mach-davinci/devices-da8xx.c | 8 +- + arch/arm/mach-davinci/devices-tnetv107x.c | 4 +- + arch/arm/mach-davinci/dm355.c | 4 +- + arch/arm/mach-davinci/dm365.c | 4 +- + arch/arm/mach-davinci/dm644x.c | 4 +- + arch/arm/mach-davinci/dm646x.c | 4 +- + include/linux/platform_data/edma.h | 8 +- + 12 files changed, 272 insertions(+), 43 deletions(-) + +diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c +index a3d189d..6d2a590 100644 +--- a/arch/arm/common/edma.c ++++ b/arch/arm/common/edma.c +@@ -24,6 +24,13 @@ + #include <linux/platform_device.h> + #include <linux/io.h> + #include <linux/slab.h> ++#include <linux/edma.h> ++#include <linux/err.h> ++#include <linux/of_address.h> ++#include <linux/of_device.h> ++#include <linux/of_dma.h> ++#include <linux/of_irq.h> ++#include <linux/pm_runtime.h> + + #include <linux/platform_data/edma.h> + +@@ -1366,31 +1373,237 @@ void edma_clear_event(unsigned channel) + EXPORT_SYMBOL(edma_clear_event); + + /*-----------------------------------------------------------------------*/ ++static int edma_of_read_u32_to_s8_array(const struct device_node *np, ++ const char *propname, s8 *out_values, ++ size_t sz) ++{ ++ struct property *prop = of_find_property(np, propname, NULL); ++ const __be32 *val; ++ ++ if (!prop) ++ return -EINVAL; ++ if (!prop->value) ++ return -ENODATA; ++ if ((sz * sizeof(u32)) > prop->length) ++ return -EOVERFLOW; ++ ++ val = prop->value; ++ ++ while (sz--) ++ *out_values++ = (s8)(be32_to_cpup(val++) & 0xff); ++ ++ /* Terminate it */ ++ *out_values++ = -1; ++ *out_values++ = -1; ++ ++ return 0; ++} ++ ++static int edma_of_read_u32_to_s16_array(const struct device_node *np, ++ const char *propname, s16 *out_values, ++ size_t sz) ++{ ++ struct property *prop = of_find_property(np, propname, NULL); ++ const __be32 *val; ++ ++ if (!prop) ++ return -EINVAL; ++ if (!prop->value) ++ return -ENODATA; ++ if ((sz * sizeof(u32)) > prop->length) ++ return -EOVERFLOW; ++ ++ val = prop->value; ++ ++ while (sz--) ++ *out_values++ = (s16)(be32_to_cpup(val++) & 0xffff); ++ ++ /* Terminate it */ ++ *out_values++ = -1; ++ *out_values++ = -1; ++ ++ return 0; ++} ++ ++static int edma_of_parse_dt(struct device *dev, ++ struct device_node *node, ++ struct edma_soc_info *pdata) ++{ ++ int ret = 0; ++ u32 value; ++ struct property *prop; ++ size_t sz; ++ struct edma_rsv_info *rsv_info; ++ s16 (*rsv_chans)[2], (*rsv_slots)[2]; ++ s8 (*queue_tc_map)[2], (*queue_priority_map)[2]; ++ ++ ret = of_property_read_u32(node, "dma-channels", &value); ++ if (ret < 0) ++ return ret; ++ pdata->n_channel = value; ++ ++ ret = of_property_read_u32(node, "ti,edma-regions", &value); ++ if (ret < 0) ++ return ret; ++ pdata->n_region = value; ++ ++ ret = of_property_read_u32(node, "ti,edma-slots", &value); ++ if (ret < 0) ++ return ret; ++ pdata->n_slot = value; ++ ++ pdata->n_cc = 1; ++ /* This is unused */ ++ pdata->n_tc = 3; ++ ++ rsv_info = ++ devm_kzalloc(dev, sizeof(struct edma_rsv_info), GFP_KERNEL); ++ if (!rsv_info) ++ return -ENOMEM; ++ pdata->rsv = rsv_info; ++ ++ /* Build the reserved channel/slots arrays */ ++ prop = of_find_property(node, "ti,edma-reserved-channels", &sz); ++ if (prop) { ++ rsv_chans = devm_kzalloc(dev, ++ sz/sizeof(s16) + 2*sizeof(s16), ++ GFP_KERNEL); ++ if (!rsv_chans) ++ return -ENOMEM; ++ pdata->rsv->rsv_chans = rsv_chans; ++ ++ ret = edma_of_read_u32_to_s16_array(node, ++ "ti,edma-reserved-channels", ++ (s16 *)rsv_chans, ++ sz/sizeof(u32)); ++ if (ret < 0) ++ return ret; ++ } ++ ++ prop = of_find_property(node, "ti,edma-reserved-slots", &sz); ++ if (prop) { ++ rsv_slots = devm_kzalloc(dev, ++ sz/sizeof(s16) + 2*sizeof(s16), ++ GFP_KERNEL); ++ if (!rsv_slots) ++ return -ENOMEM; ++ pdata->rsv->rsv_slots = rsv_slots; ++ ++ ret = edma_of_read_u32_to_s16_array(node, ++ "ti,edma-reserved-slots", ++ (s16 *)rsv_slots, ++ sz/sizeof(u32)); ++ if (ret < 0) ++ return ret; ++ } ++ ++ prop = of_find_property(node, "ti,edma-queue-tc-map", &sz); ++ if (!prop) ++ return -EINVAL; ++ ++ queue_tc_map = devm_kzalloc(dev, ++ sz/sizeof(s8) + 2*sizeof(s8), ++ GFP_KERNEL); ++ if (!queue_tc_map) ++ return -ENOMEM; ++ pdata->queue_tc_mapping = queue_tc_map; ++ ++ ret = edma_of_read_u32_to_s8_array(node, ++ "ti,edma-queue-tc-map", ++ (s8 *)queue_tc_map, ++ sz/sizeof(u32)); ++ if (ret < 0) ++ return ret; ++ ++ prop = of_find_property(node, "ti,edma-queue-priority-map", &sz); ++ if (!prop) ++ return -EINVAL; ++ ++ queue_priority_map = devm_kzalloc(dev, ++ sz/sizeof(s8) + 2*sizeof(s8), ++ GFP_KERNEL); ++ if (!queue_priority_map) ++ return -ENOMEM; ++ pdata->queue_priority_mapping = queue_priority_map; ++ ++ ret = edma_of_read_u32_to_s8_array(node, ++ "ti,edma-queue-tc-map", ++ (s8 *)queue_priority_map, ++ sz/sizeof(u32)); ++ if (ret < 0) ++ return ret; ++ ++ ret = of_property_read_u32(node, "ti,edma-default-queue", &value); ++ if (ret < 0) ++ return ret; ++ pdata->default_queue = value; ++ ++ return ret; ++} ++ ++static struct of_dma_filter_info edma_filter_info = { ++ .filter_fn = edma_filter_fn, ++}; + + static int __init edma_probe(struct platform_device *pdev) + { + struct edma_soc_info **info = pdev->dev.platform_data; +- const s8 (*queue_priority_mapping)[2]; +- const s8 (*queue_tc_mapping)[2]; ++ s8 (*queue_priority_mapping)[2]; ++ s8 (*queue_tc_mapping)[2]; + int i, j, off, ln, found = 0; + int status = -1; +- const s16 (*rsv_chans)[2]; +- const s16 (*rsv_slots)[2]; ++ s16 (*rsv_chans)[2]; ++ s16 (*rsv_slots)[2]; + int irq[EDMA_MAX_CC] = {0, 0}; + int err_irq[EDMA_MAX_CC] = {0, 0}; +- struct resource *r[EDMA_MAX_CC] = {NULL}; ++ struct resource *r[EDMA_MAX_CC] = {NULL, NULL}; ++ struct resource res[EDMA_MAX_CC]; + resource_size_t len[EDMA_MAX_CC]; + char res_name[10]; + char irq_name[10]; ++ struct device_node *node = pdev->dev.of_node; ++ struct device *dev = &pdev->dev; ++ struct edma_soc_info *pdata; ++ int ret; ++ ++ if (node) { ++ pdata = devm_kzalloc(dev, ++ sizeof(struct edma_soc_info), ++ GFP_KERNEL); ++ edma_of_parse_dt(dev, node, pdata); ++ info = &pdata; ++ dma_cap_set(DMA_SLAVE, edma_filter_info.dma_cap); ++ of_dma_controller_register(dev->of_node, ++ of_dma_simple_xlate, ++ &edma_filter_info); ++ pm_runtime_enable(dev); ++ ret = pm_runtime_get_sync(dev); ++ if (IS_ERR_VALUE(ret)) { ++ dev_err(dev, "pm_runtime_get_sync() failed\n"); ++ return ret; ++ } ++ } + + if (!info) + return -ENODEV; + + for (j = 0; j < EDMA_MAX_CC; j++) { +- sprintf(res_name, "edma_cc%d", j); +- r[j] = platform_get_resource_byname(pdev, IORESOURCE_MEM, ++ if (!info[j]) { ++ if (!found) ++ return -ENODEV; ++ break; ++ } ++ if (node) { ++ ret = of_address_to_resource(node, j, &res[j]); ++ if (!IS_ERR_VALUE(ret)) ++ r[j] = &res[j]; ++ } else { ++ sprintf(res_name, "edma_cc%d", j); ++ r[j] = platform_get_resource_byname(pdev, ++ IORESOURCE_MEM, + res_name); +- if (!r[j] || !info[j]) { ++ } ++ if (!r[j]) { + if (found) + break; + else +@@ -1465,8 +1678,12 @@ static int __init edma_probe(struct platform_device *pdev) + } + } + +- sprintf(irq_name, "edma%d", j); +- irq[j] = platform_get_irq_byname(pdev, irq_name); ++ if (node) ++ irq[j] = irq_of_parse_and_map(node, 0); ++ else { ++ sprintf(irq_name, "edma%d", j); ++ irq[j] = platform_get_irq_byname(pdev, irq_name); ++ } + edma_cc[j]->irq_res_start = irq[j]; + status = request_irq(irq[j], dma_irq_handler, 0, "edma", + &pdev->dev); +@@ -1476,8 +1693,12 @@ static int __init edma_probe(struct platform_device *pdev) + goto fail; + } + +- sprintf(irq_name, "edma%d_err", j); +- err_irq[j] = platform_get_irq_byname(pdev, irq_name); ++ if (node) ++ err_irq[j] = irq_of_parse_and_map(node, 2); ++ else { ++ sprintf(irq_name, "edma%d_err", j); ++ err_irq[j] = platform_get_irq_byname(pdev, irq_name); ++ } + edma_cc[j]->irq_res_end = err_irq[j]; + status = request_irq(err_irq[j], dma_ccerr_handler, 0, + "edma_error", &pdev->dev); +@@ -1538,9 +1759,17 @@ fail1: + return status; + } + ++static const struct of_device_id edma_of_ids[] = { ++ { .compatible = "ti,edma3", }, ++ {} ++}; + + static struct platform_driver edma_driver = { +- .driver.name = "edma", ++ .driver = { ++ .name = "edma", ++ .of_match_table = edma_of_ids, ++ }, ++ .probe = edma_probe, + }; + + static int __init edma_init(void) +diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c +index 95b5e10..ffcbec1 100644 +--- a/arch/arm/mach-davinci/board-da830-evm.c ++++ b/arch/arm/mach-davinci/board-da830-evm.c +@@ -512,7 +512,7 @@ static struct davinci_i2c_platform_data da830_evm_i2c_0_pdata = { + * example: Timer, GPIO, UART events etc) on da830/omap-l137 EVM, hence + * they are being reserved for codecs on the DSP side. + */ +-static const s16 da830_dma_rsv_chans[][2] = { ++static s16 da830_dma_rsv_chans[][2] = { + /* (offset, number) */ + { 8, 2}, + {12, 2}, +@@ -521,7 +521,7 @@ static const s16 da830_dma_rsv_chans[][2] = { + {-1, -1} + }; + +-static const s16 da830_dma_rsv_slots[][2] = { ++static s16 da830_dma_rsv_slots[][2] = { + /* (offset, number) */ + { 8, 2}, + {12, 2}, +diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c +index 32ee3f8..f207965 100644 +--- a/arch/arm/mach-davinci/board-da850-evm.c ++++ b/arch/arm/mach-davinci/board-da850-evm.c +@@ -1097,7 +1097,7 @@ device_initcall(da850_evm_config_emac); + * example: Timer, GPIO, UART events etc) on da850/omap-l138 EVM, hence + * they are being reserved for codecs on the DSP side. + */ +-static const s16 da850_dma0_rsv_chans[][2] = { ++static s16 da850_dma0_rsv_chans[][2] = { + /* (offset, number) */ + { 8, 6}, + {24, 4}, +@@ -1105,7 +1105,7 @@ static const s16 da850_dma0_rsv_chans[][2] = { + {-1, -1} + }; + +-static const s16 da850_dma0_rsv_slots[][2] = { ++static s16 da850_dma0_rsv_slots[][2] = { + /* (offset, number) */ + { 8, 6}, + {24, 4}, +@@ -1113,14 +1113,14 @@ static const s16 da850_dma0_rsv_slots[][2] = { + {-1, -1} + }; + +-static const s16 da850_dma1_rsv_chans[][2] = { ++static s16 da850_dma1_rsv_chans[][2] = { + /* (offset, number) */ + { 0, 28}, + {30, 2}, + {-1, -1} + }; + +-static const s16 da850_dma1_rsv_slots[][2] = { ++static s16 da850_dma1_rsv_slots[][2] = { + /* (offset, number) */ + { 0, 28}, + {30, 90}, +diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c +index 1dbf85b..6c5b814 100644 +--- a/arch/arm/mach-davinci/board-dm646x-evm.c ++++ b/arch/arm/mach-davinci/board-dm646x-evm.c +@@ -764,7 +764,7 @@ static struct davinci_uart_config uart_config __initdata = { + * example: Timer, GPIO, UART events etc) on dm646x, hence they are being + * reserved for codecs on the DSP side. + */ +-static const s16 dm646x_dma_rsv_chans[][2] = { ++static s16 dm646x_dma_rsv_chans[][2] = { + /* (offset, number) */ + { 0, 4}, + {13, 3}, +@@ -774,7 +774,7 @@ static const s16 dm646x_dma_rsv_chans[][2] = { + {-1, -1} + }; + +-static const s16 dm646x_dma_rsv_slots[][2] = { ++static s16 dm646x_dma_rsv_slots[][2] = { + /* (offset, number) */ + { 0, 4}, + {13, 3}, +diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c +index dc1208e..09c34f8 100644 +--- a/arch/arm/mach-davinci/board-omapl138-hawk.c ++++ b/arch/arm/mach-davinci/board-omapl138-hawk.c +@@ -70,7 +70,7 @@ static __init void omapl138_hawk_config_emac(void) + * example: Timer, GPIO, UART events etc) on da850/omap-l138 EVM/Hawkboard, + * hence they are being reserved for codecs on the DSP side. + */ +-static const s16 da850_dma0_rsv_chans[][2] = { ++static s16 da850_dma0_rsv_chans[][2] = { + /* (offset, number) */ + { 8, 6}, + {24, 4}, +@@ -78,7 +78,7 @@ static const s16 da850_dma0_rsv_chans[][2] = { + {-1, -1} + }; + +-static const s16 da850_dma0_rsv_slots[][2] = { ++static s16 da850_dma0_rsv_slots[][2] = { + /* (offset, number) */ + { 8, 6}, + {24, 4}, +@@ -86,14 +86,14 @@ static const s16 da850_dma0_rsv_slots[][2] = { + {-1, -1} + }; + +-static const s16 da850_dma1_rsv_chans[][2] = { ++static s16 da850_dma1_rsv_chans[][2] = { + /* (offset, number) */ + { 0, 28}, + {30, 2}, + {-1, -1} + }; + +-static const s16 da850_dma1_rsv_slots[][2] = { ++static s16 da850_dma1_rsv_slots[][2] = { + /* (offset, number) */ + { 0, 28}, + {30, 90}, +diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c +index bd2f72b..1f9c6ff 100644 +--- a/arch/arm/mach-davinci/devices-da8xx.c ++++ b/arch/arm/mach-davinci/devices-da8xx.c +@@ -103,27 +103,27 @@ struct platform_device da8xx_serial_device = { + }, + }; + +-static const s8 da8xx_queue_tc_mapping[][2] = { ++static s8 da8xx_queue_tc_mapping[][2] = { + /* {event queue no, TC no} */ + {0, 0}, + {1, 1}, + {-1, -1} + }; + +-static const s8 da8xx_queue_priority_mapping[][2] = { ++static s8 da8xx_queue_priority_mapping[][2] = { + /* {event queue no, Priority} */ + {0, 3}, + {1, 7}, + {-1, -1} + }; + +-static const s8 da850_queue_tc_mapping[][2] = { ++static s8 da850_queue_tc_mapping[][2] = { + /* {event queue no, TC no} */ + {0, 0}, + {-1, -1} + }; + +-static const s8 da850_queue_priority_mapping[][2] = { ++static s8 da850_queue_priority_mapping[][2] = { + /* {event queue no, Priority} */ + {0, 3}, + {-1, -1} +diff --git a/arch/arm/mach-davinci/devices-tnetv107x.c b/arch/arm/mach-davinci/devices-tnetv107x.c +index 59efd7f..d2453c9 100644 +--- a/arch/arm/mach-davinci/devices-tnetv107x.c ++++ b/arch/arm/mach-davinci/devices-tnetv107x.c +@@ -58,14 +58,14 @@ + #define TNETV107X_DMACH_SDIO1_RX 28 + #define TNETV107X_DMACH_SDIO1_TX 29 + +-static const s8 edma_tc_mapping[][2] = { ++static s8 edma_tc_mapping[][2] = { + /* event queue no TC no */ + { 0, 0 }, + { 1, 1 }, + { -1, -1 } + }; + +-static const s8 edma_priority_mapping[][2] = { ++static s8 edma_priority_mapping[][2] = { + /* event queue no Prio */ + { 0, 3 }, + { 1, 7 }, +diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c +index b165c27..cdefef3 100644 +--- a/arch/arm/mach-davinci/dm355.c ++++ b/arch/arm/mach-davinci/dm355.c +@@ -567,7 +567,7 @@ static u8 dm355_default_priorities[DAVINCI_N_AINTC_IRQ] = { + + /*----------------------------------------------------------------------*/ + +-static const s8 ++static s8 + queue_tc_mapping[][2] = { + /* {event queue no, TC no} */ + {0, 0}, +@@ -575,7 +575,7 @@ queue_tc_mapping[][2] = { + {-1, -1}, + }; + +-static const s8 ++static s8 + queue_priority_mapping[][2] = { + /* {event queue no, Priority} */ + {0, 3}, +diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c +index a611716..801e162 100644 +--- a/arch/arm/mach-davinci/dm365.c ++++ b/arch/arm/mach-davinci/dm365.c +@@ -822,7 +822,7 @@ static u8 dm365_default_priorities[DAVINCI_N_AINTC_IRQ] = { + }; + + /* Four Transfer Controllers on DM365 */ +-static const s8 ++static s8 + dm365_queue_tc_mapping[][2] = { + /* {event queue no, TC no} */ + {0, 0}, +@@ -832,7 +832,7 @@ dm365_queue_tc_mapping[][2] = { + {-1, -1}, + }; + +-static const s8 ++static s8 + dm365_queue_priority_mapping[][2] = { + /* {event queue no, Priority} */ + {0, 7}, +diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c +index 90f5639..4799fd9 100644 +--- a/arch/arm/mach-davinci/dm644x.c ++++ b/arch/arm/mach-davinci/dm644x.c +@@ -497,7 +497,7 @@ static u8 dm644x_default_priorities[DAVINCI_N_AINTC_IRQ] = { + + /*----------------------------------------------------------------------*/ + +-static const s8 ++static s8 + queue_tc_mapping[][2] = { + /* {event queue no, TC no} */ + {0, 0}, +@@ -505,7 +505,7 @@ queue_tc_mapping[][2] = { + {-1, -1}, + }; + +-static const s8 ++static s8 + queue_priority_mapping[][2] = { + /* {event queue no, Priority} */ + {0, 3}, +diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c +index 08f9dab..b4a4da6 100644 +--- a/arch/arm/mach-davinci/dm646x.c ++++ b/arch/arm/mach-davinci/dm646x.c +@@ -531,7 +531,7 @@ static u8 dm646x_default_priorities[DAVINCI_N_AINTC_IRQ] = { + /*----------------------------------------------------------------------*/ + + /* Four Transfer Controllers on DM646x */ +-static const s8 ++static s8 + dm646x_queue_tc_mapping[][2] = { + /* {event queue no, TC no} */ + {0, 0}, +@@ -541,7 +541,7 @@ dm646x_queue_tc_mapping[][2] = { + {-1, -1}, + }; + +-static const s8 ++static s8 + dm646x_queue_priority_mapping[][2] = { + /* {event queue no, Priority} */ + {0, 4}, +diff --git a/include/linux/platform_data/edma.h b/include/linux/platform_data/edma.h +index 7396f0b3..b20b586 100644 +--- a/include/linux/platform_data/edma.h ++++ b/include/linux/platform_data/edma.h +@@ -168,8 +168,8 @@ void edma_resume(unsigned channel); + + struct edma_rsv_info { + +- const s16 (*rsv_chans)[2]; +- const s16 (*rsv_slots)[2]; ++ s16 (*rsv_chans)[2]; ++ s16 (*rsv_slots)[2]; + }; + + /* platform_data for EDMA driver */ +@@ -191,8 +191,8 @@ struct edma_soc_info { + /* Resource reservation for other cores */ + struct edma_rsv_info *rsv; + +- const s8 (*queue_tc_mapping)[2]; +- const s8 (*queue_priority_mapping)[2]; ++ s8 (*queue_tc_mapping)[2]; ++ s8 (*queue_priority_mapping)[2]; + }; + + #endif diff --git a/patches/linux-3.7-rc6/0012-ARM-edma-add-AM33XX-crossbar-event-support.patch b/patches/linux-3.7-rc6/0012-ARM-edma-add-AM33XX-crossbar-event-support.patch new file mode 100644 index 0000000..87ee271 --- /dev/null +++ b/patches/linux-3.7-rc6/0012-ARM-edma-add-AM33XX-crossbar-event-support.patch @@ -0,0 +1,128 @@ +From 824b8ee82f35528d0ab1a6cf66973694a694100c Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Wed, 17 Oct 2012 16:13:17 -0400 +Subject: [PATCH] ARM: edma: add AM33XX crossbar event support + +Adds support for the per-EDMA channel event mux. This is required +for any peripherals using DMA crossbar mapped events. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + arch/arm/common/edma.c | 63 +++++++++++++++++++++++++++++++++++- + include/linux/platform_data/edma.h | 1 + + 2 files changed, 63 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c +index 6d2a590..b761b7a 100644 +--- a/arch/arm/common/edma.c ++++ b/arch/arm/common/edma.c +@@ -1425,6 +1425,53 @@ static int edma_of_read_u32_to_s16_array(const struct device_node *np, + return 0; + } + ++static int edma_xbar_event_map(struct device *dev, ++ struct device_node *node, ++ struct edma_soc_info *pdata, int len) ++{ ++ int ret = 0; ++ int i; ++ struct resource res; ++ void *xbar; ++ s16 (*xbar_chans)[2]; ++ u32 shift, offset, mux; ++ ++ xbar_chans = devm_kzalloc(dev, ++ len/sizeof(s16) + 2*sizeof(s16), ++ GFP_KERNEL); ++ if (!xbar_chans) ++ return -ENOMEM; ++ ++ ret = of_address_to_resource(node, 1, &res); ++ if (IS_ERR_VALUE(ret)) ++ return -EIO; ++ ++ xbar = devm_ioremap(dev, res.start, resource_size(&res)); ++ if (!xbar) ++ return -EIO; ++ ++ ret = edma_of_read_u32_to_s16_array(node, ++ "ti,edma-xbar-event-map", ++ (s16 *)xbar_chans, ++ len/sizeof(u32)); ++ if (IS_ERR_VALUE(ret)) ++ return -EIO; ++ ++ for (i = 0; xbar_chans[i][0] != -1; i++) { ++ shift = (xbar_chans[i][1] % 4) * 8; ++ offset = xbar_chans[i][1] >> 2; ++ offset <<= 2; ++ mux = __raw_readl((void *)((u32)xbar + offset)); ++ mux &= (~(0xff << shift)); ++ mux |= (xbar_chans[i][0] << shift); ++ __raw_writel(mux, (void *)((u32)xbar + offset)); ++ } ++ ++ pdata->xbar_chans = xbar_chans; ++ ++ return 0; ++} ++ + static int edma_of_parse_dt(struct device *dev, + struct device_node *node, + struct edma_soc_info *pdata) +@@ -1453,7 +1500,6 @@ static int edma_of_parse_dt(struct device *dev, + pdata->n_slot = value; + + pdata->n_cc = 1; +- /* This is unused */ + pdata->n_tc = 3; + + rsv_info = +@@ -1538,6 +1584,10 @@ static int edma_of_parse_dt(struct device *dev, + return ret; + pdata->default_queue = value; + ++ prop = of_find_property(node, "ti,edma-xbar-event-map", &sz); ++ if (prop) ++ ret = edma_xbar_event_map(dev, node, pdata, sz); ++ + return ret; + } + +@@ -1554,6 +1604,7 @@ static int __init edma_probe(struct platform_device *pdev) + int status = -1; + s16 (*rsv_chans)[2]; + s16 (*rsv_slots)[2]; ++ s16 (*xbar_chans)[2]; + int irq[EDMA_MAX_CC] = {0, 0}; + int err_irq[EDMA_MAX_CC] = {0, 0}; + struct resource *r[EDMA_MAX_CC] = {NULL, NULL}; +@@ -1678,6 +1729,16 @@ static int __init edma_probe(struct platform_device *pdev) + } + } + ++ /* Clear the xbar mapped channels in unused list */ ++ xbar_chans = info[j]->xbar_chans; ++ if (xbar_chans) { ++ for (i = 0; xbar_chans[i][1] != -1; i++) { ++ off = xbar_chans[i][1]; ++ clear_bits(off, 1, ++ edma_cc[j]->edma_unused); ++ } ++ } ++ + if (node) + irq[j] = irq_of_parse_and_map(node, 0); + else { +diff --git a/include/linux/platform_data/edma.h b/include/linux/platform_data/edma.h +index b20b586..888a3c6 100644 +--- a/include/linux/platform_data/edma.h ++++ b/include/linux/platform_data/edma.h +@@ -191,6 +191,7 @@ struct edma_soc_info { + /* Resource reservation for other cores */ + struct edma_rsv_info *rsv; + ++ s16 (*xbar_chans)[2]; + s8 (*queue_tc_mapping)[2]; + s8 (*queue_priority_mapping)[2]; + }; diff --git a/patches/linux-3.7-rc6/0013-dmaengine-edma-enable-build-for-AM33XX.patch b/patches/linux-3.7-rc6/0013-dmaengine-edma-enable-build-for-AM33XX.patch new file mode 100644 index 0000000..7e7fe48 --- /dev/null +++ b/patches/linux-3.7-rc6/0013-dmaengine-edma-enable-build-for-AM33XX.patch @@ -0,0 +1,25 @@ +From b0668c88fe5e7a8df4d1c8944673c2af2065d350 Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Thu, 6 Sep 2012 17:42:35 -0400 +Subject: [PATCH] dmaengine: edma: enable build for AM33XX + +Enable TI EDMA option on OMAP. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + drivers/dma/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig +index d4c1218..20ef955 100644 +--- a/drivers/dma/Kconfig ++++ b/drivers/dma/Kconfig +@@ -221,7 +221,7 @@ config SIRF_DMA + + config TI_EDMA + tristate "TI EDMA support" +- depends on ARCH_DAVINCI ++ depends on ARCH_DAVINCI || ARCH_OMAP + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + default n diff --git a/patches/linux-3.7-rc6/0014-dmaengine-edma-Add-TI-EDMA-device-tree-binding.patch b/patches/linux-3.7-rc6/0014-dmaengine-edma-Add-TI-EDMA-device-tree-binding.patch new file mode 100644 index 0000000..83a5c93 --- /dev/null +++ b/patches/linux-3.7-rc6/0014-dmaengine-edma-Add-TI-EDMA-device-tree-binding.patch @@ -0,0 +1,71 @@ +From 406954740157c140ce175107e437d15f5d74a1ba Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Thu, 20 Sep 2012 07:46:04 -0400 +Subject: [PATCH] dmaengine: edma: Add TI EDMA device tree binding + +The binding definition is based on the generic DMA controller +binding. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + Documentation/devicetree/bindings/dma/ti-edma.txt | 51 +++++++++++++++++++++ + 1 file changed, 51 insertions(+) + create mode 100644 Documentation/devicetree/bindings/dma/ti-edma.txt + +diff --git a/Documentation/devicetree/bindings/dma/ti-edma.txt b/Documentation/devicetree/bindings/dma/ti-edma.txt +new file mode 100644 +index 0000000..3344345 +--- /dev/null ++++ b/Documentation/devicetree/bindings/dma/ti-edma.txt +@@ -0,0 +1,51 @@ ++TI EDMA ++ ++Required properties: ++- compatible : "ti,edma3" ++- ti,hwmods: Name of the hwmods associated to the EDMA ++- ti,edma-regions: Number of regions ++- ti,edma-slots: Number of slots ++- ti,edma-queue-tc-map: List of transfer control to queue mappings ++- ti,edma-queue-priority-map: List of queue priority mappings ++- ti,edma-default-queue: Default queue value ++ ++Optional properties: ++- ti,edma-reserved-channels: List of reserved channel regions ++- ti,edma-reserved-slots: List of reserved slot regions ++- ti,edma-xbar-event-map: Crossbar event to channel map ++ ++Example: ++ ++edma: edma@49000000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x49000000 0x10000>; ++ interrupt-parent = <&intc>; ++ interrupts = <12 13 14>; ++ compatible = "ti,edma3"; ++ ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2"; ++ #dma-cells = <1>; ++ dma-channels = <64>; ++ ti,edma-regions = <4>; ++ ti,edma-slots = <256>; ++ ti,edma-reserved-channels = <0 2 ++ 14 2 ++ 26 6 ++ 48 4 ++ 56 8>; ++ ti,edma-reserved-slots = <0 2 ++ 14 2 ++ 26 6 ++ 48 4 ++ 56 8 ++ 64 127>; ++ ti,edma-queue-tc-map = <0 0 ++ 1 1 ++ 2 2>; ++ ti,edma-queue-priority-map = <0 0 ++ 1 1 ++ 2 2>; ++ ti,edma-default-queue = <0>; ++ ti,edma-xbar-event-map = <1 12 ++ 2 13>; ++}; diff --git a/patches/linux-3.7-rc6/0015-ARM-dts-add-AM33XX-EDMA-support.patch b/patches/linux-3.7-rc6/0015-ARM-dts-add-AM33XX-EDMA-support.patch new file mode 100644 index 0000000..85a10ac --- /dev/null +++ b/patches/linux-3.7-rc6/0015-ARM-dts-add-AM33XX-EDMA-support.patch @@ -0,0 +1,55 @@ +From 0a343eb46473df01ad66d7975f4b17ee8a0ba833 Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Wed, 10 Oct 2012 10:01:33 -0400 +Subject: [PATCH] ARM: dts: add AM33XX EDMA support + +Adds AM33XX EDMA support to the am33xx.dtsi as documented in +Documentation/devicetree/bindings/dma/ti-edma.txt + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + arch/arm/boot/dts/am33xx.dtsi | 31 +++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi +index bb31bff..ab9c78f 100644 +--- a/arch/arm/boot/dts/am33xx.dtsi ++++ b/arch/arm/boot/dts/am33xx.dtsi +@@ -62,6 +62,37 @@ + reg = <0x48200000 0x1000>; + }; + ++ edma: edma@49000000 { ++ compatible = "ti,edma3"; ++ ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2"; ++ reg = <0x49000000 0x10000>, ++ <0x44e10f90 0x10>; ++ interrupt-parent = <&intc>; ++ interrupts = <12 13 14>; ++ #dma-cells = <1>; ++ dma-channels = <64>; ++ ti,edma-regions = <4>; ++ ti,edma-slots = <256>; ++ ti,edma-reserved-channels = <0 2 ++ 14 2 ++ 26 6 ++ 48 4 ++ 56 8>; ++ ti,edma-reserved-slots = <0 2 ++ 14 2 ++ 26 6 ++ 48 4 ++ 56 8 ++ 64 127>; ++ ti,edma-queue-tc-map = <0 0 ++ 1 1 ++ 2 2>; ++ ti,edma-queue-priority-map = <0 0 ++ 1 1 ++ 2 2>; ++ ti,edma-default-queue = <0>; ++ }; ++ + gpio1: gpio@44e07000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio1"; diff --git a/patches/linux-3.7-rc6/0016-dmaengine-add-dma_request_slave_channel_compat.patch b/patches/linux-3.7-rc6/0016-dmaengine-add-dma_request_slave_channel_compat.patch new file mode 100644 index 0000000..cc70c89 --- /dev/null +++ b/patches/linux-3.7-rc6/0016-dmaengine-add-dma_request_slave_channel_compat.patch @@ -0,0 +1,42 @@ +From 4b29b8fc42201109ebfe6dc14e5b778f33f8331f Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Thu, 11 Oct 2012 12:58:44 -0400 +Subject: [PATCH] dmaengine: add dma_request_slave_channel_compat() + +Adds a dma_request_slave_channel_compat() wrapper which accepts +both the arguments from dma_request_channel() and +dma_request_slave_channel(). Based on whether the driver is +instantiated via DT, the appropriate channel request call will be +made. + +This allows for a much cleaner migration of drivers to the +dmaengine DT API as platforms continue to be mixed between those +that boot using DT and those that do not. + +Suggested-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Matt Porter <mporter@ti.com> +--- + include/linux/dmaengine.h | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h +index c88f302..11d9e25 100644 +--- a/include/linux/dmaengine.h ++++ b/include/linux/dmaengine.h +@@ -1007,6 +1007,16 @@ void dma_run_dependencies(struct dma_async_tx_descriptor *tx); + struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type); + struct dma_chan *net_dma_find_channel(void); + #define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y) ++static inline struct dma_chan ++*dma_request_slave_channel_compat(dma_cap_mask_t mask, dma_filter_fn fn, ++ void *fn_param, struct device *dev, ++ char *name) ++{ ++ if (dev->of_node) ++ return dma_request_slave_channel(dev, name); ++ else ++ return dma_request_channel(mask, fn, fn_param); ++} + + /* --- Helper iov-locking functions --- */ + diff --git a/patches/linux-3.7-rc6/0017-mmc-omap_hsmmc-convert-to-dma_request_slave_channel_.patch b/patches/linux-3.7-rc6/0017-mmc-omap_hsmmc-convert-to-dma_request_slave_channel_.patch new file mode 100644 index 0000000..60efa50 --- /dev/null +++ b/patches/linux-3.7-rc6/0017-mmc-omap_hsmmc-convert-to-dma_request_slave_channel_.patch @@ -0,0 +1,45 @@ +From eac7b54ca639d29ca6e2bdf421aa609b6a17ca0f Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Thu, 6 Sep 2012 17:47:21 -0400 +Subject: [PATCH] mmc: omap_hsmmc: convert to + dma_request_slave_channel_compat() + +Convert dmaengine channel requests to use +dma_request_slave_channel_compat(). This supports the DT case of +platforms requiring channel selection from either the OMAP DMA or +the EDMA engine. AM33xx only boots from DT and is the only user +implementing EDMA so in the !DT case we can default to the OMAP DMA +filter. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + drivers/mmc/host/omap_hsmmc.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c +index fedd258..f74141e 100644 +--- a/drivers/mmc/host/omap_hsmmc.c ++++ b/drivers/mmc/host/omap_hsmmc.c +@@ -1871,14 +1871,20 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + +- host->rx_chan = dma_request_channel(mask, omap_dma_filter_fn, &rx_req); ++ host->rx_chan = ++ dma_request_slave_channel_compat(mask, omap_dma_filter_fn, ++ &rx_req, &pdev->dev, "rx"); ++ + if (!host->rx_chan) { + dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req); + ret = -ENXIO; + goto err_irq; + } + +- host->tx_chan = dma_request_channel(mask, omap_dma_filter_fn, &tx_req); ++ host->tx_chan = ++ dma_request_slave_channel_compat(mask, omap_dma_filter_fn, ++ &tx_req, &pdev->dev, "tx"); ++ + if (!host->tx_chan) { + dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req); + ret = -ENXIO; diff --git a/patches/linux-3.7-rc6/0018-mmc-omap_hsmmc-limit-max_segs-with-the-EDMA-DMAC.patch b/patches/linux-3.7-rc6/0018-mmc-omap_hsmmc-limit-max_segs-with-the-EDMA-DMAC.patch new file mode 100644 index 0000000..36ab8ae --- /dev/null +++ b/patches/linux-3.7-rc6/0018-mmc-omap_hsmmc-limit-max_segs-with-the-EDMA-DMAC.patch @@ -0,0 +1,39 @@ +From f64e173af16724e4dbdc727821ae060a3fab459e Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Thu, 20 Sep 2012 08:55:41 -0400 +Subject: [PATCH] mmc: omap_hsmmc: limit max_segs with the EDMA DMAC + +The EDMA DMAC has a hardware limitation that prevents supporting +scatter gather lists with any number of segments. Since the EDMA +DMA Engine driver sets the maximum segments to 16, we do the +same. + +TODO: this will be replaced once the DMA Engine API supports an +API to query the DMAC's segment size limit. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + drivers/mmc/host/omap_hsmmc.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c +index f74141e..4fe62b0 100644 +--- a/drivers/mmc/host/omap_hsmmc.c ++++ b/drivers/mmc/host/omap_hsmmc.c +@@ -1833,6 +1833,16 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) + * as we want. */ + mmc->max_segs = 1024; + ++ /* Eventually we should get our max_segs limitation for EDMA by ++ * querying the dmaengine API */ ++ if (pdev->dev.of_node) { ++ struct device_node *parent = pdev->dev.of_node->parent; ++ struct device_node *node; ++ node = of_find_node_by_name(parent, "edma"); ++ if (node) ++ mmc->max_segs = 16; ++ } ++ + mmc->max_blk_size = 512; /* Block Length at max can be 1024 */ + mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */ + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; diff --git a/patches/linux-3.7-rc6/0019-mmc-omap_hsmmc-add-generic-DMA-request-support-to-th.patch b/patches/linux-3.7-rc6/0019-mmc-omap_hsmmc-add-generic-DMA-request-support-to-th.patch new file mode 100644 index 0000000..e01d8fe --- /dev/null +++ b/patches/linux-3.7-rc6/0019-mmc-omap_hsmmc-add-generic-DMA-request-support-to-th.patch @@ -0,0 +1,55 @@ +From fc9e3599817da4fb14ed9e9bb876cb4dc901a47c Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Thu, 20 Sep 2012 07:47:47 -0400 +Subject: [PATCH] mmc: omap_hsmmc: add generic DMA request support to the DT + binding + +The binding definition is based on the generic DMA request binding. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + .../devicetree/bindings/mmc/ti-omap-hsmmc.txt | 25 +++++++++++++++++++- + 1 file changed, 24 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt +index be76a23..d1b8932 100644 +--- a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt ++++ b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt +@@ -19,8 +19,28 @@ ti,dual-volt: boolean, supports dual voltage cards + "supply-name" examples are "vmmc", "vmmc_aux" etc + ti,non-removable: non-removable slot (like eMMC) + ti,needs-special-reset: Requires a special softreset sequence ++dmas: DMA controller phandle and DMA request value ordered pair ++One tx and one rx pair is required. ++dma-names: DMA request names. These strings correspond 1:1 with ++the ordered pairs in dmas. The RX request must be "rx" and the ++TX request must be "tx". ++ ++Examples: ++ ++[hwmod populated DMA resources] ++ ++ mmc1: mmc@0x4809c000 { ++ compatible = "ti,omap4-hsmmc"; ++ reg = <0x4809c000 0x400>; ++ ti,hwmods = "mmc1"; ++ ti,dual-volt; ++ bus-width = <4>; ++ vmmc-supply = <&vmmc>; /* phandle to regulator node */ ++ ti,non-removable; ++ }; ++ ++[generic DMA request binding] + +-Example: + mmc1: mmc@0x4809c000 { + compatible = "ti,omap4-hsmmc"; + reg = <0x4809c000 0x400>; +@@ -29,4 +49,7 @@ Example: + bus-width = <4>; + vmmc-supply = <&vmmc>; /* phandle to regulator node */ + ti,non-removable; ++ dmas = <&edma 24 ++ &edma 25>; ++ dma-names = "tx", "rx"; + }; diff --git a/patches/linux-3.7-rc6/0020-ARM-dts-add-AM33XX-MMC-support.patch b/patches/linux-3.7-rc6/0020-ARM-dts-add-AM33XX-MMC-support.patch new file mode 100644 index 0000000..9a2423c --- /dev/null +++ b/patches/linux-3.7-rc6/0020-ARM-dts-add-AM33XX-MMC-support.patch @@ -0,0 +1,91 @@ +From 2eafee121ee4f7c3175da0fc3415c8c79474beee Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Wed, 10 Oct 2012 15:14:03 -0400 +Subject: [PATCH] ARM: dts: add AM33XX MMC support + +Adds AM33XX MMC support for am335x-bone and am335x-evm. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + arch/arm/boot/dts/am335x-bone.dts | 6 ++++++ + arch/arm/boot/dts/am335x-evm.dts | 6 ++++++ + arch/arm/boot/dts/am33xx.dtsi | 27 +++++++++++++++++++++++++++ + 3 files changed, 39 insertions(+) + +diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts +index c634f87..5510979 100644 +--- a/arch/arm/boot/dts/am335x-bone.dts ++++ b/arch/arm/boot/dts/am335x-bone.dts +@@ -70,6 +70,8 @@ + }; + + ldo3_reg: regulator@5 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + +@@ -78,3 +80,7 @@ + }; + }; + }; ++ ++&mmc1 { ++ vmmc-supply = <&ldo3_reg>; ++}; +diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts +index 185d632..d63fce8 100644 +--- a/arch/arm/boot/dts/am335x-evm.dts ++++ b/arch/arm/boot/dts/am335x-evm.dts +@@ -114,7 +114,13 @@ + }; + + vmmc_reg: regulator@12 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; ++ ++&mmc1 { ++ vmmc-supply = <&vmmc_reg>; ++}; +diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi +index ab9c78f..26a6af7 100644 +--- a/arch/arm/boot/dts/am33xx.dtsi ++++ b/arch/arm/boot/dts/am33xx.dtsi +@@ -234,6 +234,33 @@ + status = "disabled"; + }; + ++ mmc1: mmc@48060000 { ++ compatible = "ti,omap3-hsmmc"; ++ ti,hwmods = "mmc1"; ++ ti,dual-volt; ++ ti,needs-special-reset; ++ dmas = <&edma 24 ++ &edma 25>; ++ dma-names = "tx", "rx"; ++ }; ++ ++ mmc2: mmc@481d8000 { ++ compatible = "ti,omap3-hsmmc"; ++ ti,hwmods = "mmc2"; ++ ti,needs-special-reset; ++ dmas = <&edma 2 ++ &edma 3>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ mmc3: mmc@47810000 { ++ compatible = "ti,omap3-hsmmc"; ++ ti,hwmods = "mmc3"; ++ ti,needs-special-reset; ++ status = "disabled"; ++ }; ++ + wdt2: wdt@44e35000 { + compatible = "ti,omap3-wdt"; + ti,hwmods = "wd_timer2"; diff --git a/patches/linux-3.7-rc6/0021-spi-omap2-mcspi-convert-to-dma_request_slave_channel.patch b/patches/linux-3.7-rc6/0021-spi-omap2-mcspi-convert-to-dma_request_slave_channel.patch new file mode 100644 index 0000000..1636f82 --- /dev/null +++ b/patches/linux-3.7-rc6/0021-spi-omap2-mcspi-convert-to-dma_request_slave_channel.patch @@ -0,0 +1,119 @@ +From 588d993abc0c750ebe9a9547ead82d07e74127ad Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Thu, 20 Sep 2012 00:37:54 -0400 +Subject: [PATCH] spi: omap2-mcspi: convert to + dma_request_slave_channel_compat() + +Convert dmaengine channel requests to use +dma_request_slave_channel_compat(). This supports the DT case of +platforms requiring channel selection from either the OMAP DMA or +the EDMA engine. AM33xx only boots from DT and is the only user +implementing EDMA so in the !DT case we can default to the OMAP DMA +filter. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + drivers/spi/spi-omap2-mcspi.c | 65 ++++++++++++++++++++++++++++------------- + 1 file changed, 45 insertions(+), 20 deletions(-) + +diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c +index 3542fdc..793ae8c 100644 +--- a/drivers/spi/spi-omap2-mcspi.c ++++ b/drivers/spi/spi-omap2-mcspi.c +@@ -103,6 +103,9 @@ struct omap2_mcspi_dma { + + struct completion dma_tx_completion; + struct completion dma_rx_completion; ++ ++ char dma_rx_ch_name[14]; ++ char dma_tx_ch_name[14]; + }; + + /* use PIO for small transfers, avoiding DMA setup/teardown overhead and +@@ -819,14 +822,23 @@ static int omap2_mcspi_request_dma(struct spi_device *spi) + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + sig = mcspi_dma->dma_rx_sync_dev; +- mcspi_dma->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig); ++ ++ mcspi_dma->dma_rx = ++ dma_request_slave_channel_compat(mask, omap_dma_filter_fn, ++ &sig, &master->dev, ++ mcspi_dma->dma_rx_ch_name); ++ + if (!mcspi_dma->dma_rx) { + dev_err(&spi->dev, "no RX DMA engine channel for McSPI\n"); + return -EAGAIN; + } + + sig = mcspi_dma->dma_tx_sync_dev; +- mcspi_dma->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig); ++ mcspi_dma->dma_tx = ++ dma_request_slave_channel_compat(mask, omap_dma_filter_fn, ++ &sig, &master->dev, ++ mcspi_dma->dma_tx_ch_name); ++ + if (!mcspi_dma->dma_tx) { + dev_err(&spi->dev, "no TX DMA engine channel for McSPI\n"); + dma_release_channel(mcspi_dma->dma_rx); +@@ -1217,29 +1229,42 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev) + goto free_master; + + for (i = 0; i < master->num_chipselect; i++) { +- char dma_ch_name[14]; ++ char *dma_rx_ch_name = mcspi->dma_channels[i].dma_rx_ch_name; ++ char *dma_tx_ch_name = mcspi->dma_channels[i].dma_tx_ch_name; + struct resource *dma_res; + +- sprintf(dma_ch_name, "rx%d", i); +- dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, +- dma_ch_name); +- if (!dma_res) { +- dev_dbg(&pdev->dev, "cannot get DMA RX channel\n"); +- status = -ENODEV; +- break; +- } ++ sprintf(dma_rx_ch_name, "rx%d", i); ++ if (!pdev->dev.of_node) { ++ dma_res = ++ platform_get_resource_byname(pdev, ++ IORESOURCE_DMA, ++ dma_rx_ch_name); ++ if (!dma_res) { ++ dev_dbg(&pdev->dev, ++ "cannot get DMA RX channel\n"); ++ status = -ENODEV; ++ break; ++ } + +- mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start; +- sprintf(dma_ch_name, "tx%d", i); +- dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, +- dma_ch_name); +- if (!dma_res) { +- dev_dbg(&pdev->dev, "cannot get DMA TX channel\n"); +- status = -ENODEV; +- break; ++ mcspi->dma_channels[i].dma_rx_sync_dev = ++ dma_res->start; + } ++ sprintf(dma_tx_ch_name, "tx%d", i); ++ if (!pdev->dev.of_node) { ++ dma_res = ++ platform_get_resource_byname(pdev, ++ IORESOURCE_DMA, ++ dma_tx_ch_name); ++ if (!dma_res) { ++ dev_dbg(&pdev->dev, ++ "cannot get DMA TX channel\n"); ++ status = -ENODEV; ++ break; ++ } + +- mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start; ++ mcspi->dma_channels[i].dma_tx_sync_dev = ++ dma_res->start; ++ } + } + + if (status < 0) diff --git a/patches/linux-3.7-rc6/0022-spi-omap2-mcspi-add-generic-DMA-request-support-to-t.patch b/patches/linux-3.7-rc6/0022-spi-omap2-mcspi-add-generic-DMA-request-support-to-t.patch new file mode 100644 index 0000000..1f52e69 --- /dev/null +++ b/patches/linux-3.7-rc6/0022-spi-omap2-mcspi-add-generic-DMA-request-support-to-t.patch @@ -0,0 +1,56 @@ +From b51a573d3fa257c4dad23baf9d9ffe8aea220b11 Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Thu, 20 Sep 2012 09:21:16 -0400 +Subject: [PATCH] spi: omap2-mcspi: add generic DMA request support to the DT + binding + +The binding definition is based on the generic DMA request binding. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + Documentation/devicetree/bindings/spi/omap-spi.txt | 27 +++++++++++++++++++- + 1 file changed, 26 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/spi/omap-spi.txt b/Documentation/devicetree/bindings/spi/omap-spi.txt +index 81df374..11aff04 100644 +--- a/Documentation/devicetree/bindings/spi/omap-spi.txt ++++ b/Documentation/devicetree/bindings/spi/omap-spi.txt +@@ -7,8 +7,18 @@ Required properties: + - ti,spi-num-cs : Number of chipselect supported by the instance. + - ti,hwmods: Name of the hwmod associated to the McSPI + ++Optional properties: ++- dmas: List of DMA controller phandle and DMA request ordered ++ pairs. One tx and one rx pair is required for each chip ++ select. ++- dma-names: List of DMA request names. These strings correspond ++ 1:1 with the ordered pairs in dmas. The string naming is ++ to be "rxN" and "txN" for RX and TX requests, ++ respectively, where N equals the chip select number. + +-Example: ++Examples: ++ ++[hwmod populated DMA resources] + + mcspi1: mcspi@1 { + #address-cells = <1>; +@@ -18,3 +28,18 @@ mcspi1: mcspi@1 { + ti,spi-num-cs = <4>; + }; + ++[generic DMA request binding] ++ ++mcspi1: mcspi@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "ti,omap4-mcspi"; ++ ti,hwmods = "mcspi1"; ++ ti,spi-num-cs = <2>; ++ dmas = <&edma 42 ++ &edma 43 ++ &edma 44 ++ &edma 45>; ++ dma-names = "tx0", "rx0", "tx1", "rx1"; ++}; ++ diff --git a/patches/linux-3.7-rc6/0023-ARM-dts-add-AM33XX-SPI-support.patch b/patches/linux-3.7-rc6/0023-ARM-dts-add-AM33XX-SPI-support.patch new file mode 100644 index 0000000..8388d26 --- /dev/null +++ b/patches/linux-3.7-rc6/0023-ARM-dts-add-AM33XX-SPI-support.patch @@ -0,0 +1,124 @@ +From 3fa0e6f705cc2725d267ed19b0c76541e9d7a96b Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Thu, 11 Oct 2012 08:51:46 -0400 +Subject: [PATCH] ARM: dts: add AM33XX SPI support + +Adds AM33XX SPI support for am335x-bone and am335x-evm. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + arch/arm/boot/dts/am335x-bone.dts | 17 +++++++++++++++ + arch/arm/boot/dts/am335x-evm.dts | 9 ++++++++ + arch/arm/boot/dts/am33xx.dtsi | 43 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 69 insertions(+) + +diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts +index 5510979..23edfd8 100644 +--- a/arch/arm/boot/dts/am335x-bone.dts ++++ b/arch/arm/boot/dts/am335x-bone.dts +@@ -18,6 +18,17 @@ + reg = <0x80000000 0x10000000>; /* 256 MB */ + }; + ++ am3358_pinmux: pinmux@44e10800 { ++ spi1_pins: pinmux_spi1_pins { ++ pinctrl-single,pins = < ++ 0x190 0x13 /* mcasp0_aclkx.spi1_sclk, OUTPUT_PULLUP | MODE3 */ ++ 0x194 0x33 /* mcasp0_fsx.spi1_d0, INPUT_PULLUP | MODE3 */ ++ 0x198 0x13 /* mcasp0_axr0.spi1_d1, OUTPUT_PULLUP | MODE3 */ ++ 0x19c 0x13 /* mcasp0_ahclkr.spi1_cs0, OUTPUT_PULLUP | MODE3 */ ++ >; ++ }; ++ }; ++ + ocp { + uart1: serial@44e09000 { + status = "okay"; +@@ -84,3 +95,9 @@ + &mmc1 { + vmmc-supply = <&ldo3_reg>; + }; ++ ++&spi1 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi1_pins>; ++}; +diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts +index d63fce8..8d5f660 100644 +--- a/arch/arm/boot/dts/am335x-evm.dts ++++ b/arch/arm/boot/dts/am335x-evm.dts +@@ -124,3 +124,12 @@ + &mmc1 { + vmmc-supply = <&vmmc_reg>; + }; ++ ++&spi0 { ++ status = "okay"; ++ spi-flash@0 { ++ compatible = "spansion,s25fl064k", "m25p80"; ++ spi-max-frequency = <24000000>; ++ reg = <0>; ++ }; ++}; +diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi +index 26a6af7..063ecea 100644 +--- a/arch/arm/boot/dts/am33xx.dtsi ++++ b/arch/arm/boot/dts/am33xx.dtsi +@@ -40,6 +40,15 @@ + }; + }; + ++ am3358_pinmux: pinmux@44e10800 { ++ compatible = "pinctrl-single"; ++ reg = <0x44e10800 0x0238>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pinctrl-single,register-width = <32>; ++ pinctrl-single,function-mask = <0x7f>; ++ }; ++ + /* + * XXX: Use a flat representation of the AM33XX interconnect. + * The real AM33XX interconnect network is quite complex.Since +@@ -261,6 +270,40 @@ + status = "disabled"; + }; + ++ spi0: spi@48030000 { ++ compatible = "ti,omap4-mcspi"; ++ ti,hwmods = "spi0"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x48030000 0x400>; ++ interrupt-parent = <&intc>; ++ interrupt = <65>; ++ dmas = <&edma 16 ++ &edma 17 ++ &edma 18 ++ &edma 19>; ++ dma-names = "tx0", "rx0", "tx1", "rx1"; ++ ti,spi-num-cs = <2>; ++ status = "disabled"; ++ }; ++ ++ spi1: spi@481a0000 { ++ compatible = "ti,omap4-mcspi"; ++ ti,hwmods = "spi1"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x481a0000 0x400>; ++ interrupt-parent = <&intc>; ++ interrupt = <125>; ++ dmas = <&edma 42 ++ &edma 43 ++ &edma 44 ++ &edma 45>; ++ dma-names = "tx0", "rx0", "tx1", "rx1"; ++ ti,spi-num-cs = <2>; ++ status = "disabled"; ++ }; ++ + wdt2: wdt@44e35000 { + compatible = "ti,omap3-wdt"; + ti,hwmods = "wd_timer2"; diff --git a/patches/linux-3.7-rc6/0024-Documentation-bindings-add-spansion.patch b/patches/linux-3.7-rc6/0024-Documentation-bindings-add-spansion.patch new file mode 100644 index 0000000..8287397 --- /dev/null +++ b/patches/linux-3.7-rc6/0024-Documentation-bindings-add-spansion.patch @@ -0,0 +1,22 @@ +From edd68fd797edcb247d1bcfc8f9a6dd843af35843 Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Wed, 17 Oct 2012 17:12:09 -0400 +Subject: [PATCH] Documentation: bindings: add spansion + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt +index 54463a7..261b6d5 100644 +--- a/Documentation/devicetree/bindings/vendor-prefixes.txt ++++ b/Documentation/devicetree/bindings/vendor-prefixes.txt +@@ -47,6 +47,7 @@ sil Silicon Image + simtek + sirf SiRF Technology, Inc. + sitronix Sitronix Technology Corp. ++spansion Spansion, Inc. + st STMicroelectronics + stericsson ST-Ericsson + ti Texas Instruments diff --git a/patches/linux-3.7-rc6/0025-ARM-dts-add-BeagleBone-Adafruit-1.8-LCD-support.patch b/patches/linux-3.7-rc6/0025-ARM-dts-add-BeagleBone-Adafruit-1.8-LCD-support.patch new file mode 100644 index 0000000..a31b2a9 --- /dev/null +++ b/patches/linux-3.7-rc6/0025-ARM-dts-add-BeagleBone-Adafruit-1.8-LCD-support.patch @@ -0,0 +1,44 @@ +From 03118b0a0ad5e5249b94d87f68c1f4694155b78a Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Thu, 11 Oct 2012 08:52:54 -0400 +Subject: [PATCH] ARM: dts: add BeagleBone Adafruit 1.8 LCD support + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + arch/arm/boot/dts/am335x-bone.dts | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts +index 23edfd8..290408c 100644 +--- a/arch/arm/boot/dts/am335x-bone.dts ++++ b/arch/arm/boot/dts/am335x-bone.dts +@@ -27,6 +27,12 @@ + 0x19c 0x13 /* mcasp0_ahclkr.spi1_cs0, OUTPUT_PULLUP | MODE3 */ + >; + }; ++ lcd_pins: pinmux_lcd_pins { ++ pinctrl-single,pins = < ++ 0x1a4 0x17 /* mcasp0_fsr.gpio3_19, OUTPUT_PULLUP | MODE7 */ ++ 0x1ac 0x17 /* mcasp0_ahclkx.gpio3_21, OUTPUT_PULLUP | MODE7 */ ++ >; ++ }; + }; + + ocp { +@@ -100,4 +106,16 @@ + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&spi1_pins>; ++ ++ lcd@0 { ++ compatible = "adafruit,tft-lcd-1.8-green", "sitronix,st7735"; ++ spi-max-frequency = <8000000>; ++ reg = <0>; ++ spi-cpol; ++ spi-cpha; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&lcd_pins>; ++ st7735-rst = <&gpio4 19 0>; ++ st7735-dc = <&gpio4 21 0>; ++ }; + }; diff --git a/patches/linux-3.7-rc6/0026-misc-add-gpevt-driver.patch b/patches/linux-3.7-rc6/0026-misc-add-gpevt-driver.patch new file mode 100644 index 0000000..41df270 --- /dev/null +++ b/patches/linux-3.7-rc6/0026-misc-add-gpevt-driver.patch @@ -0,0 +1,219 @@ +From 041c51572bd5c7eb9e2f581e223fd4cfa4921656 Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Wed, 17 Oct 2012 10:48:22 -0400 +Subject: [PATCH] misc: add gpevt driver + +Simply amazing...'nuff said. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + drivers/misc/Kconfig | 6 ++ + drivers/misc/Makefile | 1 + + drivers/misc/gpevt.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 179 insertions(+) + create mode 100644 drivers/misc/gpevt.c + +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index b151b7c..cd43cbd 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -499,6 +499,12 @@ config USB_SWITCH_FSA9480 + stereo and mono audio, video, microphone and UART data to use + a common connector port. + ++config GPEVT ++ tristate "Amazing GPIO DMA Event Test Driver(tm)" ++ depends on TI_EDMA ++ help ++ Simply amazing! ++ + source "drivers/misc/c2port/Kconfig" + source "drivers/misc/eeprom/Kconfig" + source "drivers/misc/cb710/Kconfig" +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index 2129377..661d093 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -49,3 +49,4 @@ obj-y += carma/ + obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o + obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ + obj-$(CONFIG_INTEL_MEI) += mei/ ++obj-$(CONFIG_GPEVT) += gpevt.o +diff --git a/drivers/misc/gpevt.c b/drivers/misc/gpevt.c +new file mode 100644 +index 0000000..4fe256c +--- /dev/null ++++ b/drivers/misc/gpevt.c +@@ -0,0 +1,172 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/irq.h> ++#include <linux/dma-mapping.h> ++#include <linux/dmaengine.h> ++#include <linux/gpio.h> ++#include <linux/err.h> ++#include <linux/uaccess.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_gpio.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/platform_device.h> ++ ++#define GPEVT_MAGIC 0xdeadbeef ++ ++static u32 *dst_fifo; ++static dma_addr_t fifo_addr; ++ ++static void gpevt_callback(void *data) ++{ ++ struct device *dev = data; ++ ++ dma_unmap_single(dev, fifo_addr, 32, DMA_FROM_DEVICE); ++ ++ if (*dst_fifo == GPEVT_MAGIC) ++ dev_info(dev, "*** DMA transfer succeeded ***\n"); ++ else ++ dev_info(dev, "*** DMA transfer failed ***\n"); ++} ++ ++static int __devinit gpevt_probe (struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct pinctrl *pinctrl; ++ struct dma_chan *chan; ++ struct dma_slave_config cfg; ++ struct dma_async_tx_descriptor *tx; ++ int gpio_evt = 0; ++ int ret; ++ u32 *src_buf; ++ struct scatterlist sg; ++ ++ src_buf = devm_kzalloc(&pdev->dev, 32, GFP_KERNEL); ++ if (!src_buf) { ++ dev_err(&pdev->dev, "failed to allocate src buffer\n"); ++ return -ENOMEM; ++ } ++ ++ dst_fifo = devm_kzalloc(&pdev->dev, 32, GFP_KERNEL); ++ if (!dst_fifo) { ++ dev_err(&pdev->dev, "failed to allocate dst fifo\n"); ++ return -ENOMEM; ++ } ++ ++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev); ++ if (IS_ERR(pinctrl)) ++ dev_warn(&pdev->dev, ++ "pins are not configured from the driver\n"); ++ ++ gpio_evt = of_get_named_gpio(np, "gpio-evt", 0); ++ if (gpio_evt < 0) { ++ dev_err(&pdev->dev, "failed to find gpio event signal!\n"); ++ return -EINVAL; ++ } ++ ++ ret = devm_gpio_request_one(&pdev->dev, gpio_evt, ++ GPIOF_IN, "GPIO Event Pin"); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to claim gpio-evt pin\n"); ++ return ret; ++ } ++ ++ ret = request_irq(gpio_to_irq(gpio_evt), no_action, ++ IRQ_TYPE_EDGE_FALLING, "gpevt", &pdev->dev); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to request falling edge irq/event\n"); ++ return ret; ++ } ++ ++ chan = dma_request_slave_channel(&pdev->dev, "gpioevt"); ++ if (!chan) { ++ dev_err(&pdev->dev, "no gpio channel for gpevt\n"); ++ return -EAGAIN; ++ } ++ ++ fifo_addr = dma_map_single(&pdev->dev, dst_fifo, 32, DMA_FROM_DEVICE); ++ if (!fifo_addr) { ++ dev_err(&pdev->dev, "could not map dst fifo\n"); ++ return -EIO; ++ } ++ cfg.dst_addr = fifo_addr; ++ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ cfg.dst_maxburst = 1; ++ ++ ret = dmaengine_slave_config(chan, &cfg); ++ if (ret) ++ return ret; ++ ++ *src_buf = GPEVT_MAGIC; ++ sg_init_table(&sg, 1); ++ sg_dma_address(&sg) = dma_map_single(&pdev->dev, src_buf, 32, DMA_TO_DEVICE); ++ sg_dma_len(&sg) = 4; ++ ++ tx = dmaengine_prep_slave_sg(chan, &sg, 1, DMA_MEM_TO_DEV, ++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK); ++ if (!tx) { ++ dev_err(&pdev->dev, "prep_slave_sg() failed\n"); ++ return -EIO; ++ } ++ ++ tx->callback = gpevt_callback; ++ tx->callback_param = &pdev->dev; ++ dmaengine_submit(tx); ++ ++ dma_async_issue_pending(chan); ++ ++ dev_info(&pdev->dev, "Amazing GPIO DMA Event Test Driver(tm) engaged\n"); ++ ++ return 0; ++} ++ ++static int __devexit gpevt_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id gpevt_dt_ids[] = { ++ { .compatible = "gpevt", .data = (void *) NULL, }, ++}; ++MODULE_DEVICE_TABLE(of, gpevt_dt_ids); ++ ++static struct platform_driver gpevt_driver = { ++ .driver = { ++ .name = "gpevt", ++ .owner = THIS_MODULE, ++ .of_match_table = gpevt_dt_ids, ++ }, ++ .probe = gpevt_probe, ++ .remove = __devexit_p(gpevt_remove), ++}; ++ ++static int __init gpevt_init(void) ++{ ++ return platform_driver_register(&gpevt_driver); ++} ++ ++static void __exit gpevt_exit(void) ++{ ++ platform_driver_unregister(&gpevt_driver); ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++module_init(gpevt_init); ++module_exit(gpevt_exit); ++ ++MODULE_DESCRIPTION("Amazing GPIO DMA Event Test Driver(tm)"); ++MODULE_AUTHOR("Matt Porter <mporter@ti.com>"); ++MODULE_LICENSE("GPL"); diff --git a/patches/linux-3.7-rc6/0027-ARM-dts-add-BeagleBone-gpevt-support.patch b/patches/linux-3.7-rc6/0027-ARM-dts-add-BeagleBone-gpevt-support.patch new file mode 100644 index 0000000..48f0f4b --- /dev/null +++ b/patches/linux-3.7-rc6/0027-ARM-dts-add-BeagleBone-gpevt-support.patch @@ -0,0 +1,50 @@ +From de9cf3f43a2bc994e0c1f4d21c8b0ff63eb3dfda Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Wed, 17 Oct 2012 17:12:45 -0400 +Subject: [PATCH] ARM: dts: add BeagleBone gpevt support + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + arch/arm/boot/dts/am335x-bone.dts | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts +index 290408c..2ad3914 100644 +--- a/arch/arm/boot/dts/am335x-bone.dts ++++ b/arch/arm/boot/dts/am335x-bone.dts +@@ -33,6 +33,11 @@ + 0x1ac 0x17 /* mcasp0_ahclkx.gpio3_21, OUTPUT_PULLUP | MODE7 */ + >; + }; ++ gpevt_pins: pinmux_gpevt_pins { ++ pinctrl-single,pins = < ++ 0x090 0x37 /* gpmc_advn_ale.gpio2_2, INPUT_PULLUP | MODE7 */ ++ >; ++ }; + }; + + ocp { +@@ -49,6 +54,15 @@ + }; + + }; ++ ++ gpevt { ++ compatible = "gpevt"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&gpevt_pins>; ++ dmas = <&edma 12>; ++ dma-names = "gpioevt"; ++ gpio-evt = <&gpio3 2 0>; ++ }; + }; + }; + +@@ -119,3 +133,7 @@ + st7735-dc = <&gpio4 21 0>; + }; + }; ++ ++&edma { ++ ti,edma-xbar-event-map = <32 12>; ++}; diff --git a/patches/linux-3.7-rc6/0028-ARM-configs-working-AM33XX-edma-dmaengine-defconfig.patch b/patches/linux-3.7-rc6/0028-ARM-configs-working-AM33XX-edma-dmaengine-defconfig.patch new file mode 100644 index 0000000..6f69da0 --- /dev/null +++ b/patches/linux-3.7-rc6/0028-ARM-configs-working-AM33XX-edma-dmaengine-defconfig.patch @@ -0,0 +1,235 @@ +From 21a9326ab1c0c135deee4490c2a5f8a07140c318 Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Fri, 12 Oct 2012 16:52:55 -0400 +Subject: [PATCH] ARM: configs: working AM33XX edma dmaengine defconfig + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + arch/arm/configs/omap2plus_defconfig | 68 ++++++++++++++++++++-------------- + 1 file changed, 40 insertions(+), 28 deletions(-) + +diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig +index 6230304..89e1c58 100644 +--- a/arch/arm/configs/omap2plus_defconfig ++++ b/arch/arm/configs/omap2plus_defconfig +@@ -1,14 +1,15 @@ + CONFIG_EXPERIMENTAL=y + CONFIG_SYSVIPC=y + CONFIG_POSIX_MQUEUE=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=y + CONFIG_BSD_PROCESS_ACCT=y + CONFIG_IKCONFIG=y + CONFIG_IKCONFIG_PROC=y + CONFIG_LOG_BUF_SHIFT=16 ++CONFIG_CGROUPS=y + CONFIG_BLK_DEV_INITRD=y + CONFIG_EXPERT=y +-# CONFIG_SYSCTL_SYSCALL is not set +-CONFIG_KALLSYMS_EXTRA_PASS=y + CONFIG_SLAB=y + CONFIG_PROFILING=y + CONFIG_OPROFILE=y +@@ -20,19 +21,20 @@ CONFIG_MODULE_FORCE_UNLOAD=y + CONFIG_MODVERSIONS=y + CONFIG_MODULE_SRCVERSION_ALL=y + # CONFIG_BLK_DEV_BSG is not set ++CONFIG_PARTITION_ADVANCED=y + CONFIG_ARCH_OMAP=y + CONFIG_OMAP_RESET_CLOCKS=y + CONFIG_OMAP_MUX_DEBUG=y ++CONFIG_SOC_OMAP5=y + CONFIG_ARM_THUMBEE=y + CONFIG_ARM_ERRATA_411920=y +-CONFIG_NO_HZ=y +-CONFIG_HIGH_RES_TIMERS=y + CONFIG_SMP=y + CONFIG_NR_CPUS=2 +-CONFIG_LEDS=y + CONFIG_ZBOOT_ROM_TEXT=0x0 + CONFIG_ZBOOT_ROM_BSS=0x0 +-CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200" ++CONFIG_ARM_APPENDED_DTB=y ++CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO0,115200" ++CONFIG_CMDLINE_FORCE=y + CONFIG_KEXEC=y + CONFIG_FPE_NWFPE=y + CONFIG_BINFMT_MISC=y +@@ -52,18 +54,24 @@ CONFIG_IP_PNP_RARP=y + # CONFIG_INET_LRO is not set + # CONFIG_IPV6 is not set + CONFIG_NETFILTER=y +-CONFIG_BT=m ++CONFIG_BT=y + CONFIG_BT_HCIUART=m + CONFIG_BT_HCIUART_H4=y + CONFIG_BT_HCIUART_BCSP=y + CONFIG_BT_HCIUART_LL=y + CONFIG_BT_HCIBCM203X=m + CONFIG_BT_HCIBPA10X=m +-CONFIG_CFG80211=m +-CONFIG_MAC80211=m ++CONFIG_CFG80211=y ++CONFIG_NL80211_TESTMODE=y ++CONFIG_CFG80211_DEBUGFS=y ++CONFIG_CFG80211_WEXT=y ++CONFIG_LIB80211=y ++CONFIG_MAC80211=y + CONFIG_MAC80211_RC_PID=y + CONFIG_MAC80211_RC_DEFAULT_PID=y + CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y + CONFIG_CONNECTOR=y + CONFIG_MTD=y + CONFIG_MTD_CMDLINE_PARTS=y +@@ -72,6 +80,7 @@ CONFIG_MTD_BLOCK=y + CONFIG_MTD_OOPS=y + CONFIG_MTD_CFI=y + CONFIG_MTD_CFI_INTELEXT=y ++CONFIG_MTD_M25P80=y + CONFIG_MTD_NAND=y + CONFIG_MTD_NAND_OMAP2=y + CONFIG_MTD_ONENAND=y +@@ -81,28 +90,27 @@ CONFIG_MTD_UBI=y + CONFIG_BLK_DEV_LOOP=y + CONFIG_BLK_DEV_RAM=y + CONFIG_BLK_DEV_RAM_SIZE=16384 ++CONFIG_GPEVT=y + CONFIG_SCSI=y + CONFIG_BLK_DEV_SD=y + CONFIG_SCSI_MULTI_LUN=y + CONFIG_SCSI_SCAN_ASYNC=y + CONFIG_MD=y + CONFIG_NETDEVICES=y +-CONFIG_SMSC_PHY=y +-CONFIG_NET_ETHERNET=y +-CONFIG_SMC91X=y +-CONFIG_SMSC911X=y + CONFIG_KS8851=y + CONFIG_KS8851_MLL=y +-CONFIG_LIBERTAS=m +-CONFIG_LIBERTAS_USB=m +-CONFIG_LIBERTAS_SDIO=m +-CONFIG_LIBERTAS_DEBUG=y ++CONFIG_SMC91X=y ++CONFIG_SMSC911X=y ++CONFIG_SMSC_PHY=y + CONFIG_USB_USBNET=y + CONFIG_USB_NET_SMSC95XX=y + CONFIG_USB_ALI_M5632=y + CONFIG_USB_AN2720=y + CONFIG_USB_EPSON2888=y + CONFIG_USB_KC2190=y ++CONFIG_WL_TI=y ++CONFIG_WL12XX=y ++CONFIG_WLCORE_SDIO=y + CONFIG_INPUT_JOYDEV=y + CONFIG_INPUT_EVDEV=y + CONFIG_KEYBOARD_GPIO=y +@@ -123,23 +131,29 @@ CONFIG_HW_RANDOM=y + CONFIG_I2C_CHARDEV=y + CONFIG_SPI=y + CONFIG_SPI_OMAP24XX=y ++CONFIG_DEBUG_PINCTRL=y + CONFIG_PINCTRL_SINGLE=y + CONFIG_DEBUG_GPIO=y + CONFIG_GPIO_SYSFS=y ++CONFIG_GPIO_GENERIC_PLATFORM=y + CONFIG_GPIO_TWL4030=y + CONFIG_W1=y + CONFIG_POWER_SUPPLY=y + CONFIG_WATCHDOG=y + CONFIG_OMAP_WATCHDOG=y + CONFIG_TWL4030_WATCHDOG=y +-CONFIG_REGULATOR_TWL4030=y ++CONFIG_MFD_TPS65217=y ++CONFIG_MFD_TPS65910=y + CONFIG_REGULATOR_TPS65023=y + CONFIG_REGULATOR_TPS6507X=y ++CONFIG_REGULATOR_TPS65217=y ++CONFIG_REGULATOR_TPS65910=y ++CONFIG_REGULATOR_TWL4030=y + CONFIG_FB=y + CONFIG_FIRMWARE_EDID=y + CONFIG_FB_MODE_HELPERS=y + CONFIG_FB_TILEBLITTING=y +-CONFIG_FB_OMAP_LCD_VGA=y ++CONFIG_FB_ST7735=y + CONFIG_OMAP2_DSS=m + CONFIG_OMAP2_DSS_RFBI=y + CONFIG_OMAP2_DSS_SDI=y +@@ -154,7 +168,6 @@ CONFIG_PANEL_ACX565AKM=m + CONFIG_BACKLIGHT_LCD_SUPPORT=y + CONFIG_LCD_CLASS_DEVICE=y + CONFIG_LCD_PLATFORM=y +-CONFIG_DISPLAY_SUPPORT=y + CONFIG_FRAMEBUFFER_CONSOLE=y + CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y + CONFIG_FONTS=y +@@ -174,12 +187,10 @@ CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m + CONFIG_USB=y + CONFIG_USB_DEBUG=y + CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +-CONFIG_USB_DEVICEFS=y + CONFIG_USB_SUSPEND=y + CONFIG_USB_MON=y + CONFIG_USB_WDM=y + CONFIG_USB_STORAGE=y +-CONFIG_USB_LIBUSUAL=y + CONFIG_USB_TEST=y + CONFIG_USB_GADGET=y + CONFIG_USB_GADGET_DEBUG=y +@@ -192,9 +203,13 @@ CONFIG_SDIO_UART=y + CONFIG_MMC_OMAP=y + CONFIG_MMC_OMAP_HS=y + CONFIG_RTC_CLASS=y ++# CONFIG_RTC_INTF_SYSFS is not set ++# CONFIG_RTC_INTF_PROC is not set ++# CONFIG_RTC_INTF_DEV is not set + CONFIG_RTC_DRV_TWL92330=y + CONFIG_RTC_DRV_TWL4030=y + CONFIG_DMADEVICES=y ++CONFIG_TI_EDMA=y + CONFIG_DMA_OMAP=y + CONFIG_EXT2_FS=y + CONFIG_EXT3_FS=y +@@ -202,6 +217,7 @@ CONFIG_EXT3_FS=y + CONFIG_EXT4_FS=y + CONFIG_QUOTA=y + CONFIG_QFMT_V2=y ++CONFIG_AUTOFS4_FS=y + CONFIG_MSDOS_FS=y + CONFIG_VFAT_FS=y + CONFIG_TMPFS=y +@@ -214,23 +230,20 @@ CONFIG_JFFS2_RUBIN=y + CONFIG_UBIFS_FS=y + CONFIG_CRAMFS=y + CONFIG_NFS_FS=y +-CONFIG_NFS_V3=y + CONFIG_NFS_V3_ACL=y + CONFIG_NFS_V4=y + CONFIG_ROOT_NFS=y +-CONFIG_PARTITION_ADVANCED=y + CONFIG_NLS_CODEPAGE_437=y + CONFIG_NLS_ISO8859_1=y + CONFIG_PRINTK_TIME=y + CONFIG_MAGIC_SYSRQ=y +-CONFIG_DEBUG_KERNEL=y + CONFIG_SCHEDSTATS=y + CONFIG_TIMER_STATS=y + CONFIG_PROVE_LOCKING=y +-CONFIG_DEBUG_SPINLOCK_SLEEP=y + # CONFIG_DEBUG_BUGVERBOSE is not set + CONFIG_DEBUG_INFO=y +-# CONFIG_RCU_CPU_STALL_DETECTOR is not set ++CONFIG_DEBUG_LL=y ++CONFIG_EARLY_PRINTK=y + CONFIG_SECURITY=y + CONFIG_CRYPTO_MICHAEL_MIC=y + # CONFIG_CRYPTO_ANSI_CPRNG is not set +@@ -239,4 +252,3 @@ CONFIG_CRC_T10DIF=y + CONFIG_CRC_ITU_T=y + CONFIG_CRC7=y + CONFIG_LIBCRC32C=y +-CONFIG_SOC_OMAP5=y diff --git a/patches/linux-3.7-rc6/0029-ARM-configs-working-da850-edma-dmaengine-defconfig.patch b/patches/linux-3.7-rc6/0029-ARM-configs-working-da850-edma-dmaengine-defconfig.patch new file mode 100644 index 0000000..b30da0c --- /dev/null +++ b/patches/linux-3.7-rc6/0029-ARM-configs-working-da850-edma-dmaengine-defconfig.patch @@ -0,0 +1,2001 @@ +From 3e2a5b5bd5dc697a3c060f6527f22543be1be880 Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Mon, 15 Oct 2012 10:17:43 -0400 +Subject: [PATCH] ARM: configs: working da850 edma dmaengine defconfig + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + arch/arm/configs/da8xx_omapl_defconfig | 1878 +++++++++++++++++++++++++++++++- + 1 file changed, 1857 insertions(+), 21 deletions(-) + +diff --git a/arch/arm/configs/da8xx_omapl_defconfig b/arch/arm/configs/da8xx_omapl_defconfig +index 88ccde0..571445f 100644 +--- a/arch/arm/configs/da8xx_omapl_defconfig ++++ b/arch/arm/configs/da8xx_omapl_defconfig +@@ -1,129 +1,1965 @@ ++# ++# Automatically generated file; DO NOT EDIT. ++# Linux/arm 3.7.0-rc1 Kernel Configuration ++# ++CONFIG_ARM=y ++CONFIG_SYS_SUPPORTS_APM_EMULATION=y ++CONFIG_GENERIC_GPIO=y ++CONFIG_HAVE_PROC_CPU=y ++CONFIG_STACKTRACE_SUPPORT=y ++CONFIG_HAVE_LATENCYTOP_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_ZONE_DMA=y ++CONFIG_NEED_DMA_MAP_STATE=y ++CONFIG_VECTORS_BASE=0xffff0000 ++CONFIG_ARM_PATCH_PHYS_VIRT=y ++CONFIG_NEED_MACH_GPIO_H=y ++CONFIG_GENERIC_BUG=y ++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" ++CONFIG_HAVE_IRQ_WORK=y ++ ++# ++# General setup ++# + CONFIG_EXPERIMENTAL=y ++CONFIG_BROKEN_ON_SMP=y ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++CONFIG_CROSS_COMPILE="" ++CONFIG_LOCALVERSION="" ++CONFIG_LOCALVERSION_AUTO=y ++CONFIG_HAVE_KERNEL_GZIP=y ++CONFIG_HAVE_KERNEL_LZMA=y ++CONFIG_HAVE_KERNEL_XZ=y ++CONFIG_HAVE_KERNEL_LZO=y ++CONFIG_KERNEL_GZIP=y ++# CONFIG_KERNEL_LZMA is not set ++# CONFIG_KERNEL_XZ is not set ++# CONFIG_KERNEL_LZO is not set ++CONFIG_DEFAULT_HOSTNAME="(none)" + # CONFIG_SWAP is not set + CONFIG_SYSVIPC=y ++CONFIG_SYSVIPC_SYSCTL=y + CONFIG_POSIX_MQUEUE=y ++CONFIG_POSIX_MQUEUE_SYSCTL=y ++# CONFIG_FHANDLE is not set ++# CONFIG_AUDIT 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_GENERIC_IRQ_CHIP=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 ++ ++# ++# Timers subsystem ++# ++CONFIG_TICK_ONESHOT=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=y ++ ++# ++# CPU/Task time and stats accounting ++# ++CONFIG_TICK_CPU_ACCOUNTING=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++# CONFIG_TASKSTATS is not set ++ ++# ++# RCU Subsystem ++# ++CONFIG_TINY_PREEMPT_RCU=y ++CONFIG_PREEMPT_RCU=y ++# CONFIG_TREE_RCU_TRACE is not set ++# CONFIG_RCU_BOOST is not set + CONFIG_IKCONFIG=y + CONFIG_IKCONFIG_PROC=y + CONFIG_LOG_BUF_SHIFT=14 ++# CONFIG_CGROUPS is not set ++# CONFIG_CHECKPOINT_RESTORE is not set ++# CONFIG_NAMESPACES is not set ++# CONFIG_SCHED_AUTOGROUP is not set ++# CONFIG_SYSFS_DEPRECATED is not set ++# CONFIG_RELAY is not set + CONFIG_BLK_DEV_INITRD=y ++CONFIG_INITRAMFS_SOURCE="" ++CONFIG_RD_GZIP=y ++# CONFIG_RD_BZIP2 is not set ++# CONFIG_RD_LZMA is not set ++# CONFIG_RD_XZ is not set ++# CONFIG_RD_LZO is not set ++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set ++CONFIG_SYSCTL=y ++CONFIG_ANON_INODES=y + CONFIG_EXPERT=y ++CONFIG_HAVE_UID16=y ++CONFIG_UID16=y ++# CONFIG_SYSCTL_SYSCALL is not set ++CONFIG_KALLSYMS=y ++# CONFIG_KALLSYMS_ALL is not set ++CONFIG_HOTPLUG=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 is not set ++CONFIG_HAVE_PERF_EVENTS=y ++CONFIG_PERF_USE_VMALLOC=y ++ ++# ++# Kernel Performance Events And Counters ++# ++# CONFIG_PERF_EVENTS 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_KPROBES=y ++CONFIG_HAVE_KRETPROBES=y ++CONFIG_HAVE_ARCH_TRACEHOOK=y ++CONFIG_HAVE_DMA_ATTRS=y ++CONFIG_HAVE_DMA_CONTIGUOUS=y ++CONFIG_GENERIC_SMP_IDLE_THREAD=y ++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y ++CONFIG_HAVE_CLK=y ++CONFIG_HAVE_DMA_API_DEBUG=y ++CONFIG_HAVE_ARCH_JUMP_LABEL=y ++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y ++CONFIG_GENERIC_KERNEL_THREAD=y ++CONFIG_GENERIC_KERNEL_EXECVE=y ++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y ++CONFIG_MODULES_USE_ELF_REL=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=y + CONFIG_MODVERSIONS=y ++# CONFIG_MODULE_SRCVERSION_ALL is not set ++# CONFIG_MODULE_SIG is not set ++CONFIG_BLOCK=y ++CONFIG_LBDAF=y + # CONFIG_BLK_DEV_BSG is not set ++# CONFIG_BLK_DEV_BSGLIB is not set ++# CONFIG_BLK_DEV_INTEGRITY 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 is not set ++# CONFIG_MINIX_SUBPARTITION is not set ++# CONFIG_SOLARIS_X86_PARTITION is not set ++# CONFIG_UNIXWARE_DISKLABEL is not set ++# CONFIG_LDM_PARTITION 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 is not set ++# CONFIG_SYSV68_PARTITION is not set ++ ++# ++# IO Schedulers ++# ++CONFIG_IOSCHED_NOOP=y + # CONFIG_IOSCHED_DEADLINE is not set + # CONFIG_IOSCHED_CFQ is not set ++CONFIG_DEFAULT_NOOP=y ++CONFIG_DEFAULT_IOSCHED="noop" ++CONFIG_UNINLINE_SPIN_UNLOCK=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_BCM2835 is not set ++# CONFIG_ARCH_CNS3XXX is not set ++# CONFIG_ARCH_CLPS711X is not set ++# CONFIG_ARCH_GEMINI is not set ++# CONFIG_ARCH_SIRF is not set ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_EP93XX is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_MXC is not set ++# CONFIG_ARCH_MXS is not set ++# CONFIG_ARCH_NETX is not set ++# CONFIG_ARCH_H720X 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_TEGRA is not set ++# CONFIG_ARCH_PXA is not set ++# 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_U8500 is not set ++# CONFIG_ARCH_NOMADIK is not set ++# CONFIG_PLAT_SPEAR is not set + CONFIG_ARCH_DAVINCI=y ++# CONFIG_ARCH_OMAP is not set ++# CONFIG_ARCH_VT8500 is not set ++# CONFIG_ARCH_ZYNQ is not set ++CONFIG_CP_INTC=y ++ ++# ++# TI DaVinci Implementations ++# ++ ++# ++# DaVinci Core Type ++# ++# CONFIG_ARCH_DAVINCI_DM644x is not set ++# CONFIG_ARCH_DAVINCI_DM355 is not set ++# CONFIG_ARCH_DAVINCI_DM646x is not set + CONFIG_ARCH_DAVINCI_DA830=y + CONFIG_ARCH_DAVINCI_DA850=y ++CONFIG_ARCH_DAVINCI_DA8XX=y ++# CONFIG_ARCH_DAVINCI_DM365 is not set ++# CONFIG_ARCH_DAVINCI_TNETV107X is not set ++ ++# ++# DaVinci Board Type ++# ++CONFIG_MACH_DAVINCI_DA830_EVM=y ++CONFIG_DA830_UI_LCD=y ++# CONFIG_DA830_UI_NAND is not set ++CONFIG_MACH_DAVINCI_DA850_EVM=y ++CONFIG_DA850_UI_NONE=y ++# CONFIG_DA850_UI_RMII is not set ++# CONFIG_DA850_UI_SD_VIDEO_PORT is not set ++# CONFIG_DA850_WL12XX is not set ++CONFIG_GPIO_PCA953X=y ++CONFIG_KEYBOARD_GPIO_POLLED=y + CONFIG_MACH_MITYOMAPL138=y + CONFIG_MACH_OMAPL138_HAWKBOARD=y ++CONFIG_DAVINCI_MUX=y ++# CONFIG_DAVINCI_MUX_DEBUG is not set ++# CONFIG_DAVINCI_MUX_WARNINGS is not set + CONFIG_DAVINCI_RESET_CLOCKS=y +-CONFIG_NO_HZ=y +-CONFIG_HIGH_RES_TIMERS=y ++ ++# ++# Processor Type ++# ++CONFIG_CPU_ARM926T=y ++CONFIG_CPU_32v5=y ++CONFIG_CPU_ABRT_EV5TJ=y ++CONFIG_CPU_PABRT_LEGACY=y ++CONFIG_CPU_CACHE_VIVT=y ++CONFIG_CPU_COPY_V4WB=y ++CONFIG_CPU_TLB_V4WBI=y ++CONFIG_CPU_CP15=y ++CONFIG_CPU_CP15_MMU=y ++CONFIG_CPU_USE_DOMAINS=y ++ ++# ++# Processor Features ++# ++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set ++CONFIG_ARM_THUMB=y ++# CONFIG_CPU_ICACHE_DISABLE is not set ++# CONFIG_CPU_DCACHE_DISABLE is not set ++CONFIG_CPU_DCACHE_WRITETHROUGH=y ++# CONFIG_CPU_CACHE_ROUND_ROBIN is not set ++# CONFIG_CACHE_L2X0 is not set ++CONFIG_ARM_L1_CACHE_SHIFT=5 ++CONFIG_ARM_NR_BANKS=8 ++CONFIG_TI_PRIV_EDMA=y ++ ++# ++# Bus support ++# ++# CONFIG_PCI_SYSCALL is not set ++# CONFIG_PCCARD is not set ++ ++# ++# Kernel Features ++# ++CONFIG_VMSPLIT_3G=y ++# CONFIG_VMSPLIT_2G is not set ++# CONFIG_VMSPLIT_1G is not set ++CONFIG_PAGE_OFFSET=0xC0000000 ++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_AEABI=y + # CONFIG_OABI_COMPAT is not set +-CONFIG_LEDS=y ++CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y ++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set ++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set ++CONFIG_HAVE_ARCH_PFN_VALID=y ++# CONFIG_HIGHMEM is not set ++CONFIG_SELECT_MEMORY_MODEL=y ++CONFIG_FLATMEM_MANUAL=y ++CONFIG_FLATMEM=y ++CONFIG_FLAT_NODE_MEM_MAP=y ++CONFIG_HAVE_MEMBLOCK=y ++CONFIG_PAGEFLAGS_EXTENDED=y ++CONFIG_SPLIT_PTLOCK_CPUS=999999 ++CONFIG_COMPACTION=y ++CONFIG_MIGRATION=y ++# CONFIG_PHYS_ADDR_T_64BIT is not set ++CONFIG_ZONE_DMA_FLAG=1 ++CONFIG_BOUNCE=y ++CONFIG_VIRT_TO_BUS=y ++# CONFIG_KSM is not set ++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 ++CONFIG_CROSS_MEMORY_ATTACH=y ++CONFIG_NEED_PER_CPU_KM=y ++# CONFIG_CLEANCACHE 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 ++ ++# ++# Boot options ++# ++# CONFIG_USE_OF is not set ++CONFIG_ATAGS=y ++# CONFIG_DEPRECATED_PARAM_STRUCT is not set + CONFIG_ZBOOT_ROM_TEXT=0x0 + CONFIG_ZBOOT_ROM_BSS=0x0 ++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_STAT=y ++# CONFIG_CPU_FREQ_STAT_DETAILS is not set ++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set ++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set + CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y ++# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set ++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set + CONFIG_CPU_FREQ_GOV_PERFORMANCE=m + CONFIG_CPU_FREQ_GOV_POWERSAVE=m ++CONFIG_CPU_FREQ_GOV_USERSPACE=y + CONFIG_CPU_FREQ_GOV_ONDEMAND=m ++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set ++ ++# ++# 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_CPU_IDLE=y ++CONFIG_CPU_IDLE_GOV_LADDER=y ++CONFIG_CPU_IDLE_GOV_MENU=y ++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set ++ ++# ++# Floating point emulation ++# ++ ++# ++# At least one emulation must be selected ++# ++# CONFIG_VFP is not set ++ ++# ++# Userspace binary formats ++# ++CONFIG_BINFMT_ELF=y ++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y ++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y ++CONFIG_HAVE_AOUT=y ++# CONFIG_BINFMT_AOUT is not set ++# CONFIG_BINFMT_MISC is not set ++CONFIG_COREDUMP=y ++ ++# ++# Power management options ++# ++CONFIG_SUSPEND=y ++CONFIG_SUSPEND_FREEZER=y ++CONFIG_PM_SLEEP=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_ARCH_SUSPEND_POSSIBLE=y ++CONFIG_ARM_CPU_SUSPEND=y + CONFIG_NET=y ++ ++# ++# Networking options ++# + CONFIG_PACKET=y ++# CONFIG_PACKET_DIAG is not set + CONFIG_UNIX=y ++# CONFIG_UNIX_DIAG is not set ++CONFIG_XFRM=y ++# CONFIG_XFRM_USER is not set ++# CONFIG_XFRM_SUB_POLICY is not set ++# CONFIG_XFRM_MIGRATE is not set ++# CONFIG_XFRM_STATISTICS is not set ++# CONFIG_NET_KEY is not set + CONFIG_INET=y ++# CONFIG_IP_MULTICAST is not set ++# CONFIG_IP_ADVANCED_ROUTER is not set + CONFIG_IP_PNP=y + CONFIG_IP_PNP_DHCP=y ++# CONFIG_IP_PNP_BOOTP is not set ++# CONFIG_IP_PNP_RARP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE_DEMUX 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 is not set ++# CONFIG_INET_IPCOMP is not set ++# CONFIG_INET_XFRM_TUNNEL is not set ++CONFIG_INET_TUNNEL=m ++CONFIG_INET_XFRM_MODE_TRANSPORT=y ++CONFIG_INET_XFRM_MODE_TUNNEL=y ++CONFIG_INET_XFRM_MODE_BEET=y + # CONFIG_INET_LRO is not set ++CONFIG_INET_DIAG=y ++CONFIG_INET_TCP_DIAG=y ++# CONFIG_INET_UDP_DIAG is not set ++# CONFIG_TCP_CONG_ADVANCED is not set ++CONFIG_TCP_CONG_CUBIC=y ++CONFIG_DEFAULT_TCP_CONG="cubic" ++# CONFIG_TCP_MD5SIG is not set ++CONFIG_IPV6=m ++# CONFIG_IPV6_PRIVACY is not set ++# CONFIG_IPV6_ROUTER_PREF is not set ++# CONFIG_IPV6_OPTIMISTIC_DAD is not set ++# CONFIG_INET6_AH is not set ++# CONFIG_INET6_ESP is not set ++# CONFIG_INET6_IPCOMP is not set ++# CONFIG_IPV6_MIP6 is not set ++# CONFIG_INET6_XFRM_TUNNEL is not set ++# CONFIG_INET6_TUNNEL is not set ++CONFIG_INET6_XFRM_MODE_TRANSPORT=m ++CONFIG_INET6_XFRM_MODE_TUNNEL=m ++CONFIG_INET6_XFRM_MODE_BEET=m ++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set ++CONFIG_IPV6_SIT=m ++# CONFIG_IPV6_SIT_6RD is not set ++CONFIG_IPV6_NDISC_NODETYPE=y ++# CONFIG_IPV6_TUNNEL is not set ++# CONFIG_IPV6_GRE is not set ++# CONFIG_IPV6_MULTIPLE_TABLES is not set ++# CONFIG_IPV6_MROUTE is not set ++# CONFIG_NETWORK_SECMARK is not set ++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set + CONFIG_NETFILTER=y ++# CONFIG_NETFILTER_DEBUG is not set ++CONFIG_NETFILTER_ADVANCED=y ++ ++# ++# Core Netfilter Configuration ++# ++# CONFIG_NETFILTER_NETLINK_ACCT is not set ++# CONFIG_NETFILTER_NETLINK_QUEUE is not set ++# CONFIG_NETFILTER_NETLINK_LOG is not set ++# CONFIG_NF_CONNTRACK is not set ++# CONFIG_NETFILTER_XTABLES is not set ++# CONFIG_IP_VS is not set ++ ++# ++# IP: Netfilter Configuration ++# ++# CONFIG_NF_DEFRAG_IPV4 is not set ++# CONFIG_IP_NF_QUEUE is not set ++# CONFIG_IP_NF_IPTABLES is not set ++# CONFIG_IP_NF_ARPTABLES is not set ++ ++# ++# IPv6: Netfilter Configuration ++# ++# CONFIG_NF_DEFRAG_IPV6 is not set ++# CONFIG_IP6_NF_IPTABLES is not set ++# 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 is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_NET_DSA is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_DECNET is not set ++# 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_WAN_ROUTER is not set ++# CONFIG_PHONET is not set ++# CONFIG_IEEE802154 is not set ++# CONFIG_NET_SCHED is not set ++# CONFIG_DCB is not set ++# CONFIG_BATMAN_ADV is not set ++# CONFIG_OPENVSWITCH 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 is not set ++# CONFIG_IRDA is not set ++# CONFIG_BT is not set ++# CONFIG_AF_RXRPC is not set ++CONFIG_WIRELESS=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 is not set ++# CONFIG_RFKILL_REGULATOR 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 ++# ++ ++# ++# Generic Driver Options ++# + CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++# CONFIG_DEVTMPFS is not set ++CONFIG_STANDALONE=y ++CONFIG_PREVENT_FIRMWARE_BUILD=y + # CONFIG_FW_LOADER is not set ++# CONFIG_DEBUG_DRIVER 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 is not set ++# CONFIG_CMA is not set ++ ++# ++# Bus devices ++# ++# CONFIG_OMAP_OCP2SCP is not set ++# 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_AR7_PARTS is not set ++ ++# ++# User Modules And Translation Layers ++# ++CONFIG_MTD_CHAR=y ++# CONFIG_MTD_BLKDEVS is not set ++# CONFIG_MTD_BLOCK is not set ++# CONFIG_MTD_BLOCK_RO is not set ++# 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 ++ ++# ++# 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=y ++CONFIG_M25PXX_USE_FAST_READ=y ++# 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 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_PARPORT is not set ++CONFIG_BLK_DEV=y ++# CONFIG_BLK_DEV_COW_COMMON is not set + CONFIG_BLK_DEV_LOOP=m ++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 ++# CONFIG_BLK_DEV_CRYPTOLOOP is not set ++ ++# ++# DRBD disabled because PROC_FS, INET or CONNECTOR not selected ++# ++# CONFIG_BLK_DEV_NBD is not set + CONFIG_BLK_DEV_RAM=y + CONFIG_BLK_DEV_RAM_COUNT=1 + CONFIG_BLK_DEV_RAM_SIZE=32768 ++# CONFIG_BLK_DEV_XIP 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_ICS932S401 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_BMP085_I2C is not set ++# CONFIG_BMP085_SPI is not set ++# CONFIG_USB_SWITCH_FSA9480 is not set ++# CONFIG_C2PORT is not set ++ ++# ++# EEPROM support ++# + CONFIG_EEPROM_AT24=y ++# CONFIG_EEPROM_AT25 is not set ++# CONFIG_EEPROM_LEGACY is not set ++# CONFIG_EEPROM_MAX6875 is not set ++# CONFIG_EEPROM_93CX6 is not set ++# 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 ++CONFIG_HAVE_IDE=y ++# CONFIG_IDE is not set ++ ++# ++# SCSI device support ++# ++CONFIG_SCSI_MOD=m ++# CONFIG_RAID_ATTRS is not set + CONFIG_SCSI=m ++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=m ++# CONFIG_CHR_DEV_ST is not set ++# CONFIG_CHR_DEV_OSST is not set ++# CONFIG_BLK_DEV_SR is not set ++# CONFIG_CHR_DEV_SG is not set ++# CONFIG_CHR_DEV_SCH is not set ++# CONFIG_SCSI_MULTI_LUN is not set ++# 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 is not set ++# 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 is not set ++# CONFIG_ISCSI_BOOT_SYSFS 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 is not set ++# CONFIG_TARGET_CORE is not set + CONFIG_NETDEVICES=y +-CONFIG_TUN=m +-CONFIG_LXT_PHY=y +-CONFIG_LSI_ET1011C_PHY=y +-CONFIG_NET_ETHERNET=y ++CONFIG_NET_CORE=y ++# CONFIG_BONDING is not set ++# CONFIG_DUMMY is not set ++# CONFIG_EQUALIZER is not set + CONFIG_MII=y +-CONFIG_TI_DAVINCI_EMAC=y +-# CONFIG_NETDEV_1000 is not set +-# CONFIG_NETDEV_10000 is not set ++# CONFIG_NET_TEAM is not set ++# CONFIG_MACVLAN is not set ++# CONFIG_VXLAN is not set + CONFIG_NETCONSOLE=y ++CONFIG_NETPOLL=y + CONFIG_NETPOLL_TRAP=y ++CONFIG_NET_POLL_CONTROLLER=y ++CONFIG_TUN=m ++# CONFIG_VETH is not set ++ ++# ++# CAIF transport drivers ++# ++CONFIG_ETHERNET=y ++CONFIG_NET_VENDOR_BROADCOM=y ++# CONFIG_B44 is not set ++# CONFIG_NET_CALXEDA_XGMAC is not set ++CONFIG_NET_VENDOR_CHELSIO=y ++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_NET_VENDOR_MICREL=y ++# CONFIG_KS8842 is not set ++# 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_SEEQ8005 is not set ++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_TI=y ++CONFIG_TI_DAVINCI_EMAC=y ++CONFIG_TI_DAVINCI_MDIO=y ++CONFIG_TI_DAVINCI_CPDMA=y ++# CONFIG_TI_CPSW is not set ++CONFIG_NET_VENDOR_WIZNET=y ++# CONFIG_WIZNET_W5100 is not set ++# CONFIG_WIZNET_W5300 is not set ++CONFIG_PHYLIB=y ++ ++# ++# MII PHY device drivers ++# ++# CONFIG_AMD_PHY is not set ++# CONFIG_MARVELL_PHY is not set ++# CONFIG_DAVICOM_PHY is not set ++# CONFIG_QSEMI_PHY is not set ++CONFIG_LXT_PHY=y ++# 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=y ++# CONFIG_MICREL_PHY is not set ++# CONFIG_FIXED_PHY is not set ++# CONFIG_MDIO_BITBANG is not set ++# CONFIG_MICREL_KS8995MA is not set ++# CONFIG_PPP is not set ++# CONFIG_SLIP is not set ++CONFIG_WLAN=y ++# CONFIG_HOSTAP is not set ++# CONFIG_WL_TI 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 is not set ++CONFIG_INPUT_POLLDEV=y ++# CONFIG_INPUT_SPARSEKMAP is not set ++# CONFIG_INPUT_MATRIXKMAP is not set ++ ++# ++# Userland interfaces ++# + CONFIG_INPUT_MOUSEDEV=m ++CONFIG_INPUT_MOUSEDEV_PSAUX=y ++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 ++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 ++# CONFIG_INPUT_JOYDEV is not set + CONFIG_INPUT_EVDEV=m + CONFIG_INPUT_EVBUG=m ++ ++# ++# Input Device Drivers ++# ++CONFIG_INPUT_KEYBOARD=y ++# CONFIG_KEYBOARD_ADP5588 is not set ++# CONFIG_KEYBOARD_ADP5589 is not set + CONFIG_KEYBOARD_ATKBD=m ++# CONFIG_KEYBOARD_QT1070 is not set ++# CONFIG_KEYBOARD_QT2160 is not set ++# CONFIG_KEYBOARD_LKKBD is not set + CONFIG_KEYBOARD_GPIO=y ++# CONFIG_KEYBOARD_TCA6416 is not set ++# CONFIG_KEYBOARD_TCA8418 is not set ++# CONFIG_KEYBOARD_MATRIX 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_OMAP4 is not set + CONFIG_KEYBOARD_XTKBD=m + # CONFIG_INPUT_MOUSE is not set ++# CONFIG_INPUT_JOYSTICK is not set ++# CONFIG_INPUT_TABLET is not set + 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_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_INPUT_MISC is not set ++ ++# ++# Hardware I/O ports ++# ++CONFIG_SERIO=y ++CONFIG_SERIO_SERPORT=y + CONFIG_SERIO_LIBPS2=y ++# CONFIG_SERIO_RAW is not set ++# CONFIG_SERIO_ALTERA_PS2 is not set ++# CONFIG_SERIO_PS2MULT is not set ++# CONFIG_GAMEPORT is not set ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_CONSOLE_TRANSLATIONS=y + # CONFIG_VT_CONSOLE is not set ++CONFIG_HW_CONSOLE=y ++# CONFIG_VT_HW_CONSOLE_BINDING is not set ++CONFIG_UNIX98_PTYS=y ++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set ++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_DEVKMEM=y ++ ++# ++# Serial drivers ++# + CONFIG_SERIAL_8250=y + CONFIG_SERIAL_8250_CONSOLE=y + CONFIG_SERIAL_8250_NR_UARTS=3 ++CONFIG_SERIAL_8250_RUNTIME_UARTS=3 ++# CONFIG_SERIAL_8250_EXTENDED is not set ++# CONFIG_SERIAL_8250_EM 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_TTY_PRINTK is not set ++# CONFIG_HVC_DCC is not set ++# CONFIG_IPMI_HANDLER is not set ++CONFIG_HW_RANDOM=m ++# CONFIG_HW_RANDOM_TIMERIOMEM is not set ++# CONFIG_HW_RANDOM_ATMEL is not set ++# 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_I2C=y ++CONFIG_I2C_BOARDINFO=y ++CONFIG_I2C_COMPAT=y + CONFIG_I2C_CHARDEV=y ++# CONFIG_I2C_MUX is not set ++CONFIG_I2C_HELPER_AUTO=y ++ ++# ++# I2C Hardware Bus support ++# ++ ++# ++# I2C system bus drivers (mostly embedded / system-on-chip) ++# + CONFIG_I2C_DAVINCI=y ++# 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_PARPORT_LIGHT is not set ++# CONFIG_I2C_TAOS_EVM 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=y ++CONFIG_SPI_DAVINCI=y ++# CONFIG_SPI_GPIO 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 is not set ++# CONFIG_SPI_TLE62X0 is not set ++# CONFIG_HSI is not set ++ ++# ++# PPS support ++# ++# CONFIG_PPS is not set ++ ++# ++# PPS generators support ++# ++ ++# ++# PTP clock support ++# ++ ++# ++# Enable Device Drivers -> PPS to see the PTP clock options. ++# ++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y ++CONFIG_ARCH_REQUIRE_GPIOLIB=y ++CONFIG_GPIOLIB=y ++# CONFIG_DEBUG_GPIO is not set ++# CONFIG_GPIO_SYSFS is not set ++ ++# ++# Memory mapped GPIO drivers: ++# ++# CONFIG_GPIO_GENERIC_PLATFORM is not set ++# CONFIG_GPIO_EM is not set ++ ++# ++# I2C GPIO expanders: ++# ++# CONFIG_GPIO_MAX7300 is not set ++# CONFIG_GPIO_MAX732X is not set ++# CONFIG_GPIO_PCA953X_IRQ is not set ++CONFIG_GPIO_PCF857X=y ++# CONFIG_GPIO_SX150X is not set ++# CONFIG_GPIO_ADP5588 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: ++# ++# CONFIG_W1 is not set ++# CONFIG_POWER_SUPPLY is not set ++# CONFIG_POWER_AVS is not set + # CONFIG_HWMON is not set ++# CONFIG_THERMAL is not set + CONFIG_WATCHDOG=y ++# CONFIG_WATCHDOG_CORE is not set ++# CONFIG_WATCHDOG_NOWAYOUT is not set ++ ++# ++# Watchdog Device Drivers ++# ++# CONFIG_SOFT_WATCHDOG is not set ++# CONFIG_DW_WATCHDOG is not set ++# CONFIG_DAVINCI_WATCHDOG is not set ++# CONFIG_MAX63XX_WATCHDOG 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 is not set ++# CONFIG_MFD_88PM860X is not set ++# CONFIG_MFD_88PM800 is not set ++# CONFIG_MFD_88PM805 is not set ++# CONFIG_MFD_SM501 is not set ++# CONFIG_MFD_ASIC3 is not set ++# CONFIG_HTC_EGPIO is not set ++# CONFIG_HTC_PASIC3 is not set ++# CONFIG_HTC_I2CPLD is not set ++# CONFIG_MFD_LM3533 is not set ++# CONFIG_TPS6105X is not set ++# CONFIG_TPS65010 is not set ++# CONFIG_TPS6507X is not set ++# CONFIG_MFD_TPS65217 is not set ++# CONFIG_MFD_TPS6586X is not set ++# CONFIG_MFD_TPS65910 is not set ++# CONFIG_MFD_TPS65912_I2C is not set ++# CONFIG_MFD_TPS65912_SPI is not set ++# CONFIG_TWL4030_CORE is not set ++# CONFIG_TWL6040_CORE is not set ++# CONFIG_MFD_STMPE is not set ++# CONFIG_MFD_TC3589X is not set ++# CONFIG_MFD_TMIO is not set ++# CONFIG_MFD_T7L66XB is not set ++# CONFIG_MFD_SMSC is not set ++# CONFIG_MFD_TC6387XB is not set ++# CONFIG_MFD_TC6393XB 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_PMIC_ADP5520 is not set ++# CONFIG_MFD_LP8788 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_MFD_SEC_CORE 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_MFD_PCF50633 is not set ++# CONFIG_MFD_MC13XXX_SPI is not set ++# CONFIG_MFD_MC13XXX_I2C is not set ++# CONFIG_ABX500_CORE is not set ++# CONFIG_EZX_PCAP is not set ++# CONFIG_MFD_WL1273_CORE is not set ++# CONFIG_MFD_TPS65090 is not set ++# CONFIG_MFD_AAT2870_CORE is not set ++# CONFIG_MFD_RC5T583 is not set ++# CONFIG_MFD_PALMAS is not set + CONFIG_REGULATOR=y ++# CONFIG_REGULATOR_DEBUG is not set + CONFIG_REGULATOR_DUMMY=y ++# 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_LP3971 is not set ++# CONFIG_REGULATOR_LP3972 is not set ++# CONFIG_REGULATOR_LP872X is not set ++# CONFIG_REGULATOR_TPS62360 is not set ++# CONFIG_REGULATOR_TPS65023 is not set + CONFIG_REGULATOR_TPS6507X=y ++# CONFIG_REGULATOR_TPS6524X is not set ++# CONFIG_MEDIA_SUPPORT is not set ++ ++# ++# Graphics support ++# ++# CONFIG_DRM is not set ++# CONFIG_VGASTATE is not set ++# CONFIG_VIDEO_OUTPUT_CONTROL is not set + 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=y ++# CONFIG_FB_SYS_FILLRECT is not set ++# CONFIG_FB_SYS_COPYAREA is not set ++# CONFIG_FB_SYS_IMAGEBLIT is not set ++# CONFIG_FB_FOREIGN_ENDIAN is not set ++# CONFIG_FB_SYS_FOPS is not set ++# CONFIG_FB_WMT_GE_ROPS is not set ++# CONFIG_FB_SVGALIB is not set ++# CONFIG_FB_MACMODES is not set ++# CONFIG_FB_BACKLIGHT is not set ++# CONFIG_FB_MODE_HELPERS is not set ++# CONFIG_FB_TILEBLITTING is not set ++ ++# ++# Frame buffer hardware drivers ++# ++# CONFIG_FB_S1D13XXX is not set + CONFIG_FB_DA8XX=y +-# CONFIG_VGA_CONSOLE 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_ST7735 is not set ++# CONFIG_EXYNOS_VIDEO is not set ++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set ++ ++# ++# Console display driver support ++# ++CONFIG_DUMMY_CONSOLE=y + CONFIG_FRAMEBUFFER_CONSOLE=y ++# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set ++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set ++# CONFIG_FONTS is not set ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y + CONFIG_LOGO=y +-CONFIG_SOUND=m +-CONFIG_SND=m +-CONFIG_SND_SOC=m +-CONFIG_SND_DAVINCI_SOC=m +-# CONFIG_HID_SUPPORT is not set ++CONFIG_LOGO_LINUX_MONO=y ++CONFIG_LOGO_LINUX_VGA16=y ++CONFIG_LOGO_LINUX_CLUT224=y ++CONFIG_SOUND=y ++# CONFIG_SOUND_OSS_CORE is not set ++CONFIG_SND=y ++CONFIG_SND_TIMER=y ++CONFIG_SND_PCM=y ++CONFIG_SND_COMPRESS_OFFLOAD=y ++CONFIG_SND_JACK=y ++# CONFIG_SND_SEQUENCER is not set ++# CONFIG_SND_MIXER_OSS is not set ++# CONFIG_SND_PCM_OSS is not set ++# CONFIG_SND_HRTIMER is not set ++# CONFIG_SND_DYNAMIC_MINORS is not set ++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_RAWMIDI_SEQ is not set ++# 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_DRIVERS=y ++# CONFIG_SND_DUMMY is not set ++# CONFIG_SND_ALOOP is not set ++# CONFIG_SND_MTPAV is not set ++# CONFIG_SND_SERIAL_U16550 is not set ++# CONFIG_SND_MPU401 is not set ++CONFIG_SND_ARM=y ++CONFIG_SND_SPI=y ++CONFIG_SND_SOC=y ++CONFIG_SND_DAVINCI_SOC=y ++CONFIG_SND_DAVINCI_SOC_MCASP=y ++# CONFIG_SND_DA830_SOC_EVM is not set ++CONFIG_SND_DA850_SOC_EVM=y ++# CONFIG_SND_DESIGNWARE_I2S is not set ++CONFIG_SND_SOC_I2C_AND_SPI=y ++# CONFIG_SND_SOC_ALL_CODECS is not set ++CONFIG_SND_SOC_TLV320AIC3X=y ++# CONFIG_SND_SIMPLE_CARD is not set ++# CONFIG_SOUND_PRIME is not set ++ ++# ++# HID support ++# ++CONFIG_HID=y ++# CONFIG_HIDRAW is not set ++# CONFIG_UHID is not set ++CONFIG_HID_GENERIC=y ++ ++# ++# Special HID drivers ++# ++CONFIG_USB_ARCH_HAS_OHCI=y ++# CONFIG_USB_ARCH_HAS_EHCI is not set ++# CONFIG_USB_ARCH_HAS_XHCI is not set + # CONFIG_USB_SUPPORT is not set ++CONFIG_MMC=y ++# CONFIG_MMC_DEBUG is not set ++CONFIG_MMC_UNSAFE_RESUME=y ++# CONFIG_MMC_CLKGATE is not set ++ ++# ++# MMC/SD/SDIO Card Drivers ++# ++CONFIG_MMC_BLOCK=y ++CONFIG_MMC_BLOCK_MINORS=8 ++CONFIG_MMC_BLOCK_BOUNCE=y ++# 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_DAVINCI=y ++# CONFIG_MMC_SPI is not set ++# CONFIG_MMC_DW is not set ++# CONFIG_MEMSTICK is not set ++# CONFIG_NEW_LEDS 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_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_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 ++ ++# ++# 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_OMAP=y ++CONFIG_DMADEVICES=y ++# CONFIG_DMADEVICES_DEBUG is not set ++ ++# ++# DMA Devices ++# ++# CONFIG_DW_DMAC is not set ++# CONFIG_TIMB_DMA is not set ++CONFIG_TI_EDMA=y ++CONFIG_DMA_ENGINE=y ++CONFIG_DMA_VIRTUAL_CHANNELS=y ++ ++# ++# DMA Clients ++# ++# CONFIG_NET_DMA is not set ++# CONFIG_ASYNC_TX_DMA is not set ++# CONFIG_DMATEST is not set ++# CONFIG_AUXDISPLAY is not set ++CONFIG_UIO=y ++# CONFIG_UIO_PDRV is not set ++# CONFIG_UIO_PDRV_GENIRQ is not set ++CONFIG_UIO_PRUSS=y ++ ++# ++# Virtio drivers ++# ++# CONFIG_VIRTIO_MMIO is not set ++ ++# ++# Microsoft Hyper-V guest support ++# ++# CONFIG_STAGING is not set ++CONFIG_CLKDEV_LOOKUP=y ++ ++# ++# Hardware Spinlock drivers ++# ++CONFIG_IOMMU_SUPPORT=y ++ ++# ++# Remoteproc drivers (EXPERIMENTAL) ++# ++# CONFIG_STE_MODEM_RPROC is not set ++ ++# ++# Rpmsg drivers (EXPERIMENTAL) ++# ++# CONFIG_VIRT_DRIVERS is not set ++# CONFIG_PM_DEVFREQ is not set ++# CONFIG_EXTCON is not set ++# CONFIG_MEMORY is not set ++# CONFIG_IIO is not set ++# CONFIG_PWM is not set ++ ++# ++# File systems ++# + CONFIG_EXT2_FS=y ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XIP is not set + CONFIG_EXT3_FS=y ++CONFIG_EXT3_DEFAULTS_TO_ORDERED=y ++CONFIG_EXT3_FS_XATTR=y ++# CONFIG_EXT3_FS_POSIX_ACL is not set ++# CONFIG_EXT3_FS_SECURITY is not set ++# CONFIG_EXT4_FS is not set ++CONFIG_JBD=y ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FS_MBCACHE=y ++# CONFIG_REISERFS_FS is not set ++# CONFIG_JFS_FS is not set + CONFIG_XFS_FS=m +-CONFIG_INOTIFY=y ++# CONFIG_XFS_QUOTA is not set ++# CONFIG_XFS_POSIX_ACL is not set ++# CONFIG_XFS_RT is not set ++# CONFIG_XFS_DEBUG is not set ++# CONFIG_GFS2_FS is not set ++# CONFIG_BTRFS_FS is not set ++# CONFIG_NILFS2_FS is not set ++# CONFIG_FS_POSIX_ACL is not set ++CONFIG_EXPORTFS=m ++CONFIG_FILE_LOCKING=y ++CONFIG_FSNOTIFY=y ++CONFIG_DNOTIFY=y ++CONFIG_INOTIFY_USER=y ++# CONFIG_FANOTIFY is not set ++# CONFIG_QUOTA is not set ++# CONFIG_QUOTACTL is not set + CONFIG_AUTOFS4_FS=m ++# CONFIG_FUSE_FS is not set ++ ++# ++# Caches ++# ++# CONFIG_FSCACHE is not set ++ ++# ++# CD-ROM/DVD Filesystems ++# ++# CONFIG_ISO9660_FS is not set ++# CONFIG_UDF_FS is not set ++ ++# ++# 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 is not set ++ ++# ++# 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 is not set ++# CONFIG_TMPFS_XATTR is not set ++# CONFIG_HUGETLB_PAGE is not set ++# CONFIG_CONFIGFS_FS is not set ++CONFIG_MISC_FILESYSTEMS=y ++# CONFIG_ADFS_FS is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_HFSPLUS_FS is not set ++# 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 is not set ++# CONFIG_VXFS_FS is not set + CONFIG_MINIX_FS=m ++# 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_NETWORK_FILESYSTEMS=y + CONFIG_NFS_FS=y ++CONFIG_NFS_V2=y + CONFIG_NFS_V3=y ++# CONFIG_NFS_V3_ACL is not set ++# CONFIG_NFS_V4 is not set ++# CONFIG_NFS_SWAP is not set + CONFIG_ROOT_NFS=y + CONFIG_NFSD=m + CONFIG_NFSD_V3=y +-CONFIG_SMB_FS=m +-CONFIG_PARTITION_ADVANCED=y ++# CONFIG_NFSD_V3_ACL is not set ++# CONFIG_NFSD_V4 is not set ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++CONFIG_NFS_COMMON=y ++CONFIG_SUNRPC=y ++# CONFIG_SUNRPC_DEBUG is not set ++# CONFIG_CEPH_FS is not set ++# CONFIG_CIFS 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=y ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set + CONFIG_NLS_ASCII=m + CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_MAC_ROMAN is not set ++# CONFIG_NLS_MAC_CELTIC is not set ++# CONFIG_NLS_MAC_CENTEURO is not set ++# CONFIG_NLS_MAC_CROATIAN is not set ++# CONFIG_NLS_MAC_CYRILLIC is not set ++# CONFIG_NLS_MAC_GAELIC is not set ++# CONFIG_NLS_MAC_GREEK is not set ++# CONFIG_NLS_MAC_ICELAND is not set ++# CONFIG_NLS_MAC_INUIT is not set ++# CONFIG_NLS_MAC_ROMANIAN is not set ++# CONFIG_NLS_MAC_TURKISH is not set + CONFIG_NLS_UTF8=m ++ ++# ++# Kernel hacking ++# ++# CONFIG_PRINTK_TIME is not set ++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 ++CONFIG_ENABLE_WARN_DEPRECATED=y ++CONFIG_ENABLE_MUST_CHECK=y ++CONFIG_FRAME_WARN=1024 ++# CONFIG_MAGIC_SYSRQ is not set ++# CONFIG_STRIP_ASM_SYMS is not set ++# CONFIG_READABLE_ASM is not set ++# CONFIG_UNUSED_SYMBOLS is not set + CONFIG_DEBUG_FS=y ++# CONFIG_HEADERS_CHECK is not set ++# CONFIG_DEBUG_SECTION_MISMATCH is not set + CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_SHIRQ is not set ++# CONFIG_LOCKUP_DETECTOR is not set ++# CONFIG_PANIC_ON_OOPS is not set ++CONFIG_PANIC_ON_OOPS_VALUE=0 ++# CONFIG_DETECT_HUNG_TASK is not set ++CONFIG_SCHED_DEBUG=y ++# CONFIG_SCHEDSTATS is not set + 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=y ++CONFIG_DEBUG_PI_LIST=y ++# CONFIG_RT_MUTEX_TESTER is not set ++# CONFIG_DEBUG_SPINLOCK is not set + CONFIG_DEBUG_MUTEXES=y +-# CONFIG_RCU_CPU_STALL_DETECTOR is not set ++# CONFIG_DEBUG_LOCK_ALLOC is not set ++# CONFIG_PROVE_LOCKING is not set ++# CONFIG_PROVE_RCU_DELAY is not set ++# CONFIG_SPARSE_RCU_POINTER 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_DEBUG_STACK_USAGE is not set ++# CONFIG_DEBUG_KOBJECT is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++# CONFIG_DEBUG_INFO 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 ++# CONFIG_RCU_TORTURE_TEST 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_LKDTM is not set ++# CONFIG_NOTIFIER_ERROR_INJECTION is not set ++# CONFIG_FAULT_INJECTION is not set ++# CONFIG_LATENCYTOP 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_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_SAMPLES is not set ++CONFIG_HAVE_ARCH_KGDB=y ++# CONFIG_KGDB is not set ++# CONFIG_TEST_KSTRTOX is not set ++# CONFIG_STRICT_DEVMEM is not set ++CONFIG_ARM_UNWIND=y + CONFIG_DEBUG_USER=y +-CONFIG_DEBUG_ERRORS=y ++# CONFIG_DEBUG_LL is not set ++CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" ++ ++# ++# Security options ++# ++# CONFIG_KEYS is not set ++# CONFIG_SECURITY_DMESG_RESTRICT is not set ++# CONFIG_SECURITY is not set ++# CONFIG_SECURITYFS is not set ++CONFIG_DEFAULT_SECURITY_DAC=y ++CONFIG_DEFAULT_SECURITY="" ++CONFIG_CRYPTO=y ++ ++# ++# Crypto core or helper ++# ++CONFIG_CRYPTO_ALGAPI=y ++CONFIG_CRYPTO_ALGAPI2=y ++# CONFIG_CRYPTO_MANAGER is not set ++# CONFIG_CRYPTO_MANAGER2 is not set ++# CONFIG_CRYPTO_USER is not set ++# CONFIG_CRYPTO_GF128MUL is not set ++# CONFIG_CRYPTO_NULL is not set ++# CONFIG_CRYPTO_CRYPTD is not set ++# CONFIG_CRYPTO_AUTHENC is not set ++# CONFIG_CRYPTO_TEST is not set ++ ++# ++# Authenticated Encryption with Associated Data ++# ++# CONFIG_CRYPTO_CCM is not set ++# CONFIG_CRYPTO_GCM is not set ++# CONFIG_CRYPTO_SEQIV is not set ++ ++# ++# Block modes ++# ++# CONFIG_CRYPTO_CBC is not set ++# CONFIG_CRYPTO_CTR is not set ++# CONFIG_CRYPTO_CTS is not set ++# CONFIG_CRYPTO_ECB is not set ++# CONFIG_CRYPTO_LRW is not set ++# CONFIG_CRYPTO_PCBC is not set ++# CONFIG_CRYPTO_XTS is not set ++ ++# ++# Hash modes ++# ++# CONFIG_CRYPTO_HMAC is not set ++# CONFIG_CRYPTO_XCBC is not set ++# CONFIG_CRYPTO_VMAC is not set ++ ++# ++# Digest ++# ++# CONFIG_CRYPTO_CRC32C is not set ++# CONFIG_CRYPTO_GHASH is not set ++# CONFIG_CRYPTO_MD4 is not set ++# CONFIG_CRYPTO_MD5 is not set ++# CONFIG_CRYPTO_MICHAEL_MIC is not set ++# CONFIG_CRYPTO_RMD128 is not set ++# CONFIG_CRYPTO_RMD160 is not set ++# CONFIG_CRYPTO_RMD256 is not set ++# CONFIG_CRYPTO_RMD320 is not set ++# CONFIG_CRYPTO_SHA1 is not set ++# CONFIG_CRYPTO_SHA1_ARM is not set ++# CONFIG_CRYPTO_SHA256 is not set ++# CONFIG_CRYPTO_SHA512 is not set ++# CONFIG_CRYPTO_TGR192 is not set ++# CONFIG_CRYPTO_WP512 is not set ++ ++# ++# Ciphers ++# ++CONFIG_CRYPTO_AES=y ++# CONFIG_CRYPTO_AES_ARM is not set ++# CONFIG_CRYPTO_ANUBIS is not set ++# CONFIG_CRYPTO_ARC4 is not set ++# CONFIG_CRYPTO_BLOWFISH is not set ++# CONFIG_CRYPTO_CAMELLIA is not set ++# CONFIG_CRYPTO_CAST5 is not set ++# CONFIG_CRYPTO_CAST6 is not set ++# CONFIG_CRYPTO_DES is not set ++# CONFIG_CRYPTO_FCRYPT is not set ++# CONFIG_CRYPTO_KHAZAD is not set ++# CONFIG_CRYPTO_SALSA20 is not set ++# CONFIG_CRYPTO_SEED is not set ++# CONFIG_CRYPTO_SERPENT is not set ++# CONFIG_CRYPTO_TEA is not set ++# CONFIG_CRYPTO_TWOFISH is not set ++ ++# ++# Compression ++# ++# CONFIG_CRYPTO_DEFLATE is not set ++# CONFIG_CRYPTO_ZLIB is not set ++# CONFIG_CRYPTO_LZO is not set ++ ++# ++# Random Number Generation ++# + # CONFIG_CRYPTO_ANSI_CPRNG is not set ++# CONFIG_CRYPTO_USER_API_HASH is not set ++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set + # CONFIG_CRYPTO_HW is not set ++# CONFIG_BINARY_PRINTF is not set ++ ++# ++# Library routines ++# ++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=m ++# CONFIG_CRC16 is not set + CONFIG_CRC_T10DIF=m ++# CONFIG_CRC_ITU_T is not set ++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 is not set ++# CONFIG_LIBCRC32C is not set ++# CONFIG_CRC8 is not set ++CONFIG_ZLIB_INFLATE=y ++CONFIG_LZO_COMPRESS=y ++CONFIG_LZO_DECOMPRESS=y ++# CONFIG_XZ_DEC is not set ++# CONFIG_XZ_DEC_BCJ is not set ++CONFIG_DECOMPRESS_GZIP=y ++CONFIG_GENERIC_ALLOCATOR=y ++CONFIG_HAS_IOMEM=y ++CONFIG_HAS_IOPORT=y ++CONFIG_HAS_DMA=y ++CONFIG_DQL=y ++CONFIG_NLATTR=y ++CONFIG_GENERIC_ATOMIC64=y ++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y ++# CONFIG_AVERAGE is not set ++# CONFIG_CORDIC is not set ++# CONFIG_DDR is not set diff --git a/patches/linux-3.7-rc6/0030-misc-gpevt-null-terminate-the-of_match_table.patch b/patches/linux-3.7-rc6/0030-misc-gpevt-null-terminate-the-of_match_table.patch new file mode 100644 index 0000000..5edd618 --- /dev/null +++ b/patches/linux-3.7-rc6/0030-misc-gpevt-null-terminate-the-of_match_table.patch @@ -0,0 +1,22 @@ +From 07a646411ade49a270c87332d482f4ac6f0ecfba Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Thu, 18 Oct 2012 10:29:57 -0400 +Subject: [PATCH] misc: gpevt: null terminate the of_match_table + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + drivers/misc/gpevt.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/misc/gpevt.c b/drivers/misc/gpevt.c +index 4fe256c..c0cc1a2 100644 +--- a/drivers/misc/gpevt.c ++++ b/drivers/misc/gpevt.c +@@ -139,6 +139,7 @@ static int __devexit gpevt_remove(struct platform_device *pdev) + + static const struct of_device_id gpevt_dt_ids[] = { + { .compatible = "gpevt", .data = (void *) NULL, }, ++ { }, + }; + MODULE_DEVICE_TABLE(of, gpevt_dt_ids); + diff --git a/patches/linux-3.7-rc6/0031-proposed-probe-fix-works-for-me-on-evm.patch b/patches/linux-3.7-rc6/0031-proposed-probe-fix-works-for-me-on-evm.patch new file mode 100644 index 0000000..db77068 --- /dev/null +++ b/patches/linux-3.7-rc6/0031-proposed-probe-fix-works-for-me-on-evm.patch @@ -0,0 +1,43 @@ +From 93ae8a949f58bbd1d8c77baf116c5db2654d11c6 Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Fri, 19 Oct 2012 11:24:40 -0400 +Subject: [PATCH] proposed probe fix - works for me on evm + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + arch/arm/common/edma.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c +index b761b7a..6ed394f 100644 +--- a/arch/arm/common/edma.c ++++ b/arch/arm/common/edma.c +@@ -1598,6 +1598,8 @@ static struct of_dma_filter_info edma_filter_info = { + static int __init edma_probe(struct platform_device *pdev) + { + struct edma_soc_info **info = pdev->dev.platform_data; ++ struct edma_soc_info *ninfo[EDMA_MAX_CC] = {NULL, NULL}; ++ struct edma_soc_info tmpinfo; + s8 (*queue_priority_mapping)[2]; + s8 (*queue_tc_mapping)[2]; + int i, j, off, ln, found = 0; +@@ -1614,15 +1616,13 @@ static int __init edma_probe(struct platform_device *pdev) + char irq_name[10]; + struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; +- struct edma_soc_info *pdata; + int ret; + + if (node) { +- pdata = devm_kzalloc(dev, +- sizeof(struct edma_soc_info), +- GFP_KERNEL); +- edma_of_parse_dt(dev, node, pdata); +- info = &pdata; ++ info = ninfo; ++ edma_of_parse_dt(dev, node, &tmpinfo); ++ info[0] = &tmpinfo; ++ + dma_cap_set(DMA_SLAVE, edma_filter_info.dma_cap); + of_dma_controller_register(dev->of_node, + of_dma_simple_xlate, diff --git a/patches/linux-3.7-rc6/0033-ARM-OMAP3-hwmod-Add-AM33XX-HWMOD-data-for-davinci_md.patch b/patches/linux-3.7-rc6/0033-ARM-OMAP3-hwmod-Add-AM33XX-HWMOD-data-for-davinci_md.patch new file mode 100644 index 0000000..37d6082 --- /dev/null +++ b/patches/linux-3.7-rc6/0033-ARM-OMAP3-hwmod-Add-AM33XX-HWMOD-data-for-davinci_md.patch @@ -0,0 +1,80 @@ +From 8889710c8dc2c6e67fec6124bb2c397bac5ae43d Mon Sep 17 00:00:00 2001 +From: Mugunthan V N <mugunthanvnm@ti.com> +Date: Tue, 5 Jun 2012 13:18:01 +0530 +Subject: [PATCH] ARM: OMAP3+: hwmod: Add AM33XX HWMOD data for davinci_mdio + +This patch adds minimal hwmod support for davinci mdio driver. This patch +requires rework on parent child relation between cpsw and davinci mdio +hwmod data to support runtime PM. + +Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> +--- + arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 34 ++++++++++++++++++++++++++-- + 1 file changed, 32 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +index 59d5c1c..f96bbc0 100644 +--- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c ++++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +@@ -650,8 +650,7 @@ static struct omap_hwmod_class_sysconfig am33xx_cpgmac_sysc = { + .rev_offs = 0x0, + .sysc_offs = 0x8, + .syss_offs = 0x4, +- .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE | +- SYSS_HAS_RESET_STATUS), ++ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | MSTANDBY_FORCE | + MSTANDBY_NO), + .sysc_fields = &omap_hwmod_sysc_type3, +@@ -682,6 +681,8 @@ static struct omap_hwmod am33xx_cpgmac0_hwmod = { + .modulemode = MODULEMODE_SWCTRL, + }, + }, ++ .flags = (HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY | ++ HWMOD_INIT_NO_RESET | HWMOD_INIT_NO_IDLE), + }; + + /* +@@ -2510,6 +2511,34 @@ static struct omap_hwmod_addr_space am33xx_elm_addr_space[] = { + { } + }; + ++/* mdio class */ ++static struct omap_hwmod_class am33xx_mdio_hwmod_class = { ++ .name = "davinci_mdio", ++}; ++ ++struct omap_hwmod_addr_space am33xx_mdio_addr_space[] = { ++ { ++ .pa_start = 0x4A101000, ++ .pa_end = 0x4A101000 + SZ_256 - 1, ++ .flags = ADDR_MAP_ON_INIT, ++ }, ++ { } ++}; ++ ++static struct omap_hwmod am33xx_mdio_hwmod = { ++ .name = "davinci_mdio", ++ .class = &am33xx_mdio_hwmod_class, ++ .clkdm_name = "cpsw_125mhz_clkdm", ++ .main_clk = "cpsw_125mhz_gclk", ++}; ++ ++struct omap_hwmod_ocp_if am33xx_cpgmac0__mdio = { ++ .master = &am33xx_cpgmac0_hwmod, ++ .slave = &am33xx_mdio_hwmod, ++ .addr = am33xx_mdio_addr_space, ++ .user = OCP_USER_MPU, ++}; ++ + static struct omap_hwmod_ocp_if am33xx_l4_ls__elm = { + .master = &am33xx_l4_ls_hwmod, + .slave = &am33xx_elm_hwmod, +@@ -3371,6 +3400,7 @@ static struct omap_hwmod_ocp_if *am33xx_hwmod_ocp_ifs[] __initdata = { + &am33xx_l3_main__tptc2, + &am33xx_l3_s__usbss, + &am33xx_l4_hs__cpgmac0, ++ &am33xx_cpgmac0__mdio, + NULL, + }; + diff --git a/patches/linux-3.7-rc6/0034-net-davinci_mdio-Fix-type-mistake-in-calling-runtime.patch b/patches/linux-3.7-rc6/0034-net-davinci_mdio-Fix-type-mistake-in-calling-runtime.patch new file mode 100644 index 0000000..a15b51d --- /dev/null +++ b/patches/linux-3.7-rc6/0034-net-davinci_mdio-Fix-type-mistake-in-calling-runtime.patch @@ -0,0 +1,35 @@ +From 009cf7834fb1707dd687934131d70750d037c376 Mon Sep 17 00:00:00 2001 +From: Vaibhav Hiremath <hvaibhav@ti.com> +Date: Mon, 3 Sep 2012 21:14:52 +0530 +Subject: [PATCH] net: davinci_mdio: Fix type mistake in calling runtime-pm + api + +By mistake (most likely a copy-paste), instead of pm_runtime_get_sync() +api, driver is calling pm_runtime_put_sync() api in resume callback +function. The bug was introduced by commit id (ae2c07aaf74: +davinci_mdio: runtime PM support). + +Now, the reason why it didn't impact functionality is, the patch has +been tested on AM335x-EVM and BeagleBone platform while submitting; +and in case of AM335x the MDIO driver doesn't control the module +enable/disable part, which is handled by CPSW driver. + +Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com> +Cc: Mugunthan V N <mugunthanvnm@ti.com> +--- + drivers/net/ethernet/ti/davinci_mdio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c +index 51a96db..ae74280 100644 +--- a/drivers/net/ethernet/ti/davinci_mdio.c ++++ b/drivers/net/ethernet/ti/davinci_mdio.c +@@ -465,7 +465,7 @@ static int davinci_mdio_resume(struct device *dev) + u32 ctrl; + + spin_lock(&data->lock); +- pm_runtime_put_sync(data->dev); ++ pm_runtime_get_sync(data->dev); + + /* restart the scan state machine */ + ctrl = __raw_readl(&data->regs->control); diff --git a/patches/linux-3.7-rc6/0035-net-cpsw-Add-parent-child-relation-support-between-c.patch b/patches/linux-3.7-rc6/0035-net-cpsw-Add-parent-child-relation-support-between-c.patch new file mode 100644 index 0000000..47f1029 --- /dev/null +++ b/patches/linux-3.7-rc6/0035-net-cpsw-Add-parent-child-relation-support-between-c.patch @@ -0,0 +1,87 @@ +From a96742d124907b9056fadaa90590331b93ca25dc Mon Sep 17 00:00:00 2001 +From: Vaibhav Hiremath <hvaibhav@ti.com> +Date: Mon, 3 Sep 2012 21:25:38 +0530 +Subject: [PATCH] net: cpsw: Add parent<->child relation support between cpsw + and mdio + +CPGMAC SubSystem consist of various sub-modules, like, mdio, cpdma, +cpsw, etc... These sub-modules are also used in some of Davinci family +of devices. Now based on requirement, use-case and available technology +nodes the integration of these sub-modules varies across devices. + +So coming back to Linux net driver, currently separate and independent +platform devices & drivers for CPSW and MDIO is implemented. In case of +Davinci they both has separate control, from resources perspective, +like clock. + +In case of AM33XX, the resources are shared and only one register +bit-field is provided to control module/clock enable/disable, makes it +difficult to handle common resource. + +So the solution here implemented in this patch is, + +Create parent<->child relationship between both the drivers, making +CPSW as a parent and MDIO as its child and enumerate all the child nodes +under cpsw module. +Both the drivers will function exactly the way it was operating before, +including runtime-pm functionality. No change is required in MDIO driver +(for that matter to any child driver). + +As this is only supported during DT boot, the parent<->child relationship +is created and populated in DT execution flow. The only required change +is inside DTS file, making MDIO as a child to CPSW node. + +Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com> +Cc: Mugunthan V N <mugunthanvnm@ti.com> +--- + drivers/net/ethernet/ti/cpsw.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c +index df55e24..fb1a692 100644 +--- a/drivers/net/ethernet/ti/cpsw.c ++++ b/drivers/net/ethernet/ti/cpsw.c +@@ -827,7 +827,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, + } + data->mac_control = prop; + +- for_each_child_of_node(node, slave_node) { ++ for_each_node_by_name(slave_node, "slave") { + struct cpsw_slave_data *slave_data = data->slave_data + i; + const char *phy_id = NULL; + const void *mac_addr = NULL; +@@ -862,6 +862,14 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, + i++; + } + ++ /* ++ * Populate all the child nodes here... ++ */ ++ ret = of_platform_populate(node, NULL, NULL, &pdev->dev); ++ /* We do not want to force this, as in some cases may not have child */ ++ if (ret) ++ pr_warn("Doesn't have any child node\n"); ++ + return 0; + + error_ret: +@@ -895,6 +903,11 @@ static int __devinit cpsw_probe(struct platform_device *pdev) + priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG); + priv->rx_packet_max = max(rx_packet_max, 128); + ++ /* ++ * This may be required here for child devices. ++ */ ++ pm_runtime_enable(&pdev->dev); ++ + if (cpsw_probe_dt(&priv->data, pdev)) { + pr_err("cpsw: platform data missing\n"); + ret = -ENODEV; +@@ -921,7 +934,6 @@ static int __devinit cpsw_probe(struct platform_device *pdev) + for (i = 0; i < data->slaves; i++) + priv->slaves[i].slave_num = i; + +- pm_runtime_enable(&pdev->dev); + priv->clk = clk_get(&pdev->dev, "fck"); + if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "fck is not found\n"); diff --git a/patches/linux-3.7-rc6/0036-arm-dts-am33xx-Add-cpsw-and-mdio-module-nodes-for-AM.patch b/patches/linux-3.7-rc6/0036-arm-dts-am33xx-Add-cpsw-and-mdio-module-nodes-for-AM.patch new file mode 100644 index 0000000..a61d47c --- /dev/null +++ b/patches/linux-3.7-rc6/0036-arm-dts-am33xx-Add-cpsw-and-mdio-module-nodes-for-AM.patch @@ -0,0 +1,109 @@ +From bd5fdad1c484959dadf1daf6b1d433b9e1653390 Mon Sep 17 00:00:00 2001 +From: Mugunthan V N <mugunthanvnm@ti.com> +Date: Sun, 29 Jul 2012 20:56:29 +0530 +Subject: [PATCH] arm/dts: am33xx: Add cpsw and mdio module nodes for AM33XX + +Add CPSW and MDIO related device tree data for AM33XX. +Also enable them into board/evm dts files by providing +respective phy-id. + +Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> +Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com> +--- + arch/arm/boot/dts/am335x-bone.dts | 8 ++++++ + arch/arm/boot/dts/am335x-evm.dts | 8 ++++++ + arch/arm/boot/dts/am33xx.dtsi | 50 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 66 insertions(+) + +diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts +index 2ad3914..47c17e8 100644 +--- a/arch/arm/boot/dts/am335x-bone.dts ++++ b/arch/arm/boot/dts/am335x-bone.dts +@@ -137,3 +137,11 @@ + &edma { + ti,edma-xbar-event-map = <32 12>; + }; ++ ++&cpsw_emac0 { ++ phy_id = "4a101000.mdio:00"; ++}; ++ ++&cpsw_emac1 { ++ phy_id = "4a101000.mdio:01"; ++}; +diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts +index 8d5f660..23d1e26 100644 +--- a/arch/arm/boot/dts/am335x-evm.dts ++++ b/arch/arm/boot/dts/am335x-evm.dts +@@ -133,3 +133,11 @@ + reg = <0>; + }; + }; ++ ++&cpsw_emac0 { ++ phy_id = "4a101000.mdio:00"; ++}; ++ ++&cpsw_emac1 { ++ phy_id = "4a101000.mdio:01"; ++}; +diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi +index 063ecea..a6bfd9b 100644 +--- a/arch/arm/boot/dts/am33xx.dtsi ++++ b/arch/arm/boot/dts/am33xx.dtsi +@@ -311,5 +311,55 @@ + interrupt-parent = <&intc>; + interrupts = <91>; + }; ++ ++ mac: ethernet@4A100000 { ++ compatible = "ti,cpsw"; ++ ti,hwmods = "cpgmac0"; ++ cpdma_channels = <8>; ++ host_port_no = <0>; ++ cpdma_reg_ofs = <0x800>; ++ cpdma_sram_ofs = <0xa00>; ++ ale_reg_ofs = <0xd00>; ++ ale_entries = <1024>; ++ host_port_reg_ofs = <0x108>; ++ hw_stats_reg_ofs = <0x900>; ++ bd_ram_ofs = <0x2000>; ++ bd_ram_size = <0x2000>; ++ no_bd_ram = <0>; ++ rx_descs = <64>; ++ mac_control = <0x20>; ++ slaves = <2>; ++ reg = <0x4a100000 0x800 ++ 0x4a101200 0x100 ++ 0x4a101000 0x100>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ interrupt-parent = <&intc>; ++ /* c0_rx_thresh_pend c0_rx_pend c0_tx_pend c0_misc_pend*/ ++ interrupts = <40 41 42 43>; ++ ranges; ++ cpsw_emac0: slave@0 { ++ slave_reg_ofs = <0x208>; ++ sliver_reg_ofs = <0xd80>; ++ /* Filled in by U-Boot */ ++ mac-address = [ 00 00 00 00 00 00 ]; ++ }; ++ cpsw_emac1: slave@1 { ++ slave_reg_ofs = <0x308>; ++ sliver_reg_ofs = <0xdc0>; ++ /* Filled in by U-Boot */ ++ mac-address = [ 00 00 00 00 00 00 ]; ++ }; ++ ++ davinci_mdio: mdio@4a101000 { ++ compatible = "ti,davinci_mdio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ti,hwmods = "davinci_mdio"; ++ bus_freq = <1000000>; ++ reg = <0x4a101000 0x100>; ++ }; ++ ++ }; + }; + }; diff --git a/patches/linux-3.7-rc6/0038-i2c-pinctrl-ify-i2c-omap.c.patch b/patches/linux-3.7-rc6/0038-i2c-pinctrl-ify-i2c-omap.c.patch new file mode 100644 index 0000000..e936d15 --- /dev/null +++ b/patches/linux-3.7-rc6/0038-i2c-pinctrl-ify-i2c-omap.c.patch @@ -0,0 +1,46 @@ +From 610430c8c2229f0b70e7f52188ea7dc8c368a6d6 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Fri, 14 Sep 2012 17:51:11 +0300 +Subject: [PATCH] i2c: pinctrl-ify i2c-omap.c + +Conflicts: + drivers/i2c/busses/i2c-omap.c +--- + drivers/i2c/busses/i2c-omap.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c +index db31eae..4c38aa0 100644 +--- a/drivers/i2c/busses/i2c-omap.c ++++ b/drivers/i2c/busses/i2c-omap.c +@@ -44,6 +44,8 @@ + #include <linux/i2c-omap.h> + #include <linux/pm_runtime.h> + #include <linux/pm_qos.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/err.h> + + /* I2C controller revisions */ + #define OMAP_I2C_OMAP1_REV_2 0x20 +@@ -1064,6 +1066,7 @@ omap_i2c_probe(struct platform_device *pdev) + const struct of_device_id *match; + int irq; + int r; ++ struct pinctrl *pinctrl; + + /* NOTE: driver uses the static register mapping */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -1202,6 +1205,13 @@ omap_i2c_probe(struct platform_device *pdev) + + of_i2c_register_devices(adap); + ++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev); ++ if (IS_ERR(pinctrl)) ++ dev_warn(dev->dev, "unable to select pin group\n"); ++ ++ dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", adap->nr, ++ dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); ++ + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); + diff --git a/patches/linux-3.7-rc6/0039-arm-dts-AM33XX-Configure-pinmuxs-for-user-leds-contr.patch b/patches/linux-3.7-rc6/0039-arm-dts-AM33XX-Configure-pinmuxs-for-user-leds-contr.patch new file mode 100644 index 0000000..5b16009 --- /dev/null +++ b/patches/linux-3.7-rc6/0039-arm-dts-AM33XX-Configure-pinmuxs-for-user-leds-contr.patch @@ -0,0 +1,70 @@ +From b76bec0181666391a0e7ad495a72865f1f35173d Mon Sep 17 00:00:00 2001 +From: "AnilKumar, Chimata" <anilkumar@ti.com> +Date: Fri, 31 Aug 2012 09:29:18 +0000 +Subject: [PATCH] arm/dts: AM33XX: Configure pinmuxs for user leds control on + Bone + +Adds GPIO pinctrl nodes to am3358_pinmux master node to control +user leds (USR0, USR1, USR2 and USR3) present on BeagleBone. + +Signed-off-by: AnilKumar Ch <anilkumar@ti.com> +--- + arch/arm/boot/dts/am335x-bone.dts | 38 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts +index 47c17e8..3a089c0 100644 +--- a/arch/arm/boot/dts/am335x-bone.dts ++++ b/arch/arm/boot/dts/am335x-bone.dts +@@ -38,6 +38,14 @@ + 0x090 0x37 /* gpmc_advn_ale.gpio2_2, INPUT_PULLUP | MODE7 */ + >; + }; ++ userled_pins: pinmux_userled_pins { ++ pinctrl-single,pins = < ++ 0x54 0x7 /* gpmc_a5.gpio1_21, OUTPUT | MODE7 */ ++ 0x58 0x17 /* gpmc_a6.gpio1_22, OUTPUT_PULLUP | MODE7 */ ++ 0x5c 0x7 /* gpmc_a7.gpio1_23, OUTPUT | MODE7 */ ++ 0x60 0x17 /* gpmc_a8.gpio1_24, OUTPUT_PULLUP | MODE7 */ ++ >; ++ }; + }; + + ocp { +@@ -45,6 +53,36 @@ + status = "okay"; + }; + ++ gpio-leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&userled_pins>; ++ ++ led0 { ++ label = "beaglebone:green:usr0"; ++ gpios = <&gpio2 21 0>; ++ default-state = "off"; ++ }; ++ ++ led1 { ++ label = "beaglebone:green:usr1"; ++ gpios = <&gpio2 22 0>; ++ default-state = "off"; ++ }; ++ ++ led2 { ++ label = "beaglebone:green:usr2"; ++ gpios = <&gpio2 23 0>; ++ default-state = "off"; ++ }; ++ ++ led3 { ++ label = "beaglebone:green:usr3"; ++ gpios = <&gpio2 24 0>; ++ default-state = "off"; ++ }; ++ }; ++ + i2c1: i2c@44e0b000 { + status = "okay"; + clock-frequency = <400000>; diff --git a/patches/linux-3.7-rc6/0040-beaglebone-DT-set-default-triggers-for-LEDS.patch b/patches/linux-3.7-rc6/0040-beaglebone-DT-set-default-triggers-for-LEDS.patch new file mode 100644 index 0000000..c901a64 --- /dev/null +++ b/patches/linux-3.7-rc6/0040-beaglebone-DT-set-default-triggers-for-LEDS.patch @@ -0,0 +1,29 @@ +From 1d95712aeeea071a0090699bb863004e5fae01d3 Mon Sep 17 00:00:00 2001 +From: Koen Kooi <koen@dominion.thruhere.net> +Date: Wed, 5 Sep 2012 09:49:21 +0200 +Subject: [PATCH] beaglebone DT: set default triggers for LEDS + +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/boot/dts/am335x-bone.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts +index 3a089c0..63acfb4 100644 +--- a/arch/arm/boot/dts/am335x-bone.dts ++++ b/arch/arm/boot/dts/am335x-bone.dts +@@ -61,12 +61,14 @@ + led0 { + label = "beaglebone:green:usr0"; + gpios = <&gpio2 21 0>; ++ linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + + led1 { + label = "beaglebone:green:usr1"; + gpios = <&gpio2 22 0>; ++ linux,default-trigger = "mmc0"; + default-state = "off"; + }; + diff --git a/patches/linux-3.7-rc6/0041-beaglebone-add-a-cpu-led-trigger.patch b/patches/linux-3.7-rc6/0041-beaglebone-add-a-cpu-led-trigger.patch new file mode 100644 index 0000000..e30b5cd --- /dev/null +++ b/patches/linux-3.7-rc6/0041-beaglebone-add-a-cpu-led-trigger.patch @@ -0,0 +1,22 @@ +From 1313bf938b17dca177b11f7317e8b1765c2008b0 Mon Sep 17 00:00:00 2001 +From: Koen Kooi <koen@dominion.thruhere.net> +Date: Mon, 15 Oct 2012 16:53:28 +0200 +Subject: [PATCH] beaglebone: add a cpu led trigger + +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/boot/dts/am335x-bone.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts +index 63acfb4..147bc01 100644 +--- a/arch/arm/boot/dts/am335x-bone.dts ++++ b/arch/arm/boot/dts/am335x-bone.dts +@@ -75,6 +75,7 @@ + led2 { + label = "beaglebone:green:usr2"; + gpios = <&gpio2 23 0>; ++ linux,default-trigger = "cpu0"; + default-state = "off"; + }; + diff --git a/patches/linux-3.7-rc6/0043-arm-dts-AM33XX-Add-device-tree-OPP-table.patch b/patches/linux-3.7-rc6/0043-arm-dts-AM33XX-Add-device-tree-OPP-table.patch new file mode 100644 index 0000000..6977708 --- /dev/null +++ b/patches/linux-3.7-rc6/0043-arm-dts-AM33XX-Add-device-tree-OPP-table.patch @@ -0,0 +1,79 @@ +From 6983ddebcd85a68ce206f513adea0edd80e22052 Mon Sep 17 00:00:00 2001 +From: "AnilKumar, Chimata" <anilkumar@ti.com> +Date: Fri, 31 Aug 2012 09:37:20 +0000 +Subject: [PATCH] arm/dts: AM33XX: Add device tree OPP table + +Add DT OPP table for AM33XX family of devices. This data is +decoded by OF with of_init_opp_table() helper function. + +Also adds cpu0 supply name to the corresponding dts files. +cpu0-supply name is used by cpufreq-cpu0 driver to get the +regulator pointer for voltage modifications. + +Signed-off-by: AnilKumar Ch <anilkumar@ti.com> +--- + arch/arm/boot/dts/am335x-bone.dts | 6 ++++++ + arch/arm/boot/dts/am335x-evm.dts | 6 ++++++ + arch/arm/boot/dts/am33xx.dtsi | 15 +++++++++++++++ + 3 files changed, 27 insertions(+) + +diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts +index 147bc01..87686e9 100644 +--- a/arch/arm/boot/dts/am335x-bone.dts ++++ b/arch/arm/boot/dts/am335x-bone.dts +@@ -13,6 +13,12 @@ + model = "TI AM335x BeagleBone"; + compatible = "ti,am335x-bone", "ti,am33xx"; + ++ cpus { ++ cpu@0 { ++ cpu0-supply = <&dcdc2_reg>; ++ }; ++ }; ++ + memory { + device_type = "memory"; + reg = <0x80000000 0x10000000>; /* 256 MB */ +diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts +index 23d1e26..43e23a8 100644 +--- a/arch/arm/boot/dts/am335x-evm.dts ++++ b/arch/arm/boot/dts/am335x-evm.dts +@@ -13,6 +13,12 @@ + model = "TI AM335x EVM"; + compatible = "ti,am335x-evm", "ti,am33xx"; + ++ cpus { ++ cpu@0 { ++ cpu0-supply = <&vdd1_reg>; ++ }; ++ }; ++ + memory { + device_type = "memory"; + reg = <0x80000000 0x10000000>; /* 256 MB */ +diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi +index a6bfd9b..9755276 100644 +--- a/arch/arm/boot/dts/am33xx.dtsi ++++ b/arch/arm/boot/dts/am33xx.dtsi +@@ -25,6 +25,21 @@ + cpus { + cpu@0 { + compatible = "arm,cortex-a8"; ++ ++ /* ++ * To consider voltage drop between PMIC and SoC, ++ * tolerance value is reduced to 2% from 4% and ++ * voltage value is increased as a precaution. ++ */ ++ operating-points = < ++ /* kHz uV */ ++ 720000 1285000 ++ 600000 1225000 ++ 500000 1125000 ++ 275000 1125000 ++ >; ++ voltage-tolerance = <2>; /* 2 percentage */ ++ clock-latency = <300000>; /* From omap-cpufreq driver */ + }; + }; + diff --git a/patches/linux-3.7-rc6/0045-input-TSC-ti_tscadc-Correct-register-usage.patch b/patches/linux-3.7-rc6/0045-input-TSC-ti_tscadc-Correct-register-usage.patch new file mode 100644 index 0000000..5046ca3 --- /dev/null +++ b/patches/linux-3.7-rc6/0045-input-TSC-ti_tscadc-Correct-register-usage.patch @@ -0,0 +1,226 @@ +From 26a11407fe194a39a80f8a36964d23f03ef61f7e Mon Sep 17 00:00:00 2001 +From: "Patil, Rachna" <rachna@ti.com> +Date: Tue, 16 Oct 2012 07:25:38 +0000 +Subject: [PATCH] input: TSC: ti_tscadc: Correct register usage + +This patch cleans up the wrong register definitions +and usage for touchscreen controller. +Bit masks were not defined earlier. + +For ex: consider a register define as: +write(xyz, ABC) +ABC is expected to be written to register bits 0-11. +Here we see that value written is as expected, but this write +is also affecting all the remaining bits of xyz. +The remaining bits hold the default value as 0 and the write +also sets it to zero. Hence wrong usage were not causing user +visible bugs. +Due to these reasons it was difficult to follow when +compared with TRM. + +Unused definitions are also removed. +Since there is change in some naming convention because of +all the above mentioned reasons, the same has been +updated throughout the code. +Bit declarations are grouped to increase readability. + +Signed-off-by: Patil, Rachna <rachna@ti.com> +--- + drivers/input/touchscreen/ti_tscadc.c | 128 +++++++++++++++++++++------------ + 1 file changed, 82 insertions(+), 46 deletions(-) + +diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c +index d229c74..d198cab 100644 +--- a/drivers/input/touchscreen/ti_tscadc.c ++++ b/drivers/input/touchscreen/ti_tscadc.c +@@ -52,43 +52,79 @@ + + /* Register Bitfields */ + #define IRQWKUP_ENB BIT(0) +-#define STPENB_STEPENB 0x7FFF ++ ++/* Step Enable */ ++#define STEPENB_MASK (0x1FFFF << 0) ++#define STEPENB(val) (val << 0) ++#define STPENB_STEPENB STEPENB(0x7FFF) ++ ++/* IRQ enable */ + #define IRQENB_FIFO1THRES BIT(5) + #define IRQENB_PENUP BIT(9) +-#define STEPCONFIG_MODE_HWSYNC 0x2 +-#define STEPCONFIG_SAMPLES_AVG (1 << 4) +-#define STEPCONFIG_XPP (1 << 5) +-#define STEPCONFIG_XNN (1 << 6) +-#define STEPCONFIG_YPP (1 << 7) +-#define STEPCONFIG_YNN (1 << 8) +-#define STEPCONFIG_XNP (1 << 9) +-#define STEPCONFIG_YPN (1 << 10) +-#define STEPCONFIG_INM (1 << 18) +-#define STEPCONFIG_INP (1 << 20) +-#define STEPCONFIG_INP_5 (1 << 21) +-#define STEPCONFIG_FIFO1 (1 << 26) +-#define STEPCONFIG_OPENDLY 0xff +-#define STEPCONFIG_Z1 (3 << 19) +-#define STEPIDLE_INP (1 << 22) +-#define STEPCHARGE_RFP (1 << 12) +-#define STEPCHARGE_INM (1 << 15) +-#define STEPCHARGE_INP (1 << 19) +-#define STEPCHARGE_RFM (1 << 23) +-#define STEPCHARGE_DELAY 0x1 +-#define CNTRLREG_TSCSSENB (1 << 0) +-#define CNTRLREG_STEPID (1 << 1) +-#define CNTRLREG_STEPCONFIGWRT (1 << 2) +-#define CNTRLREG_4WIRE (1 << 5) +-#define CNTRLREG_5WIRE (1 << 6) +-#define CNTRLREG_8WIRE (3 << 5) +-#define CNTRLREG_TSCENB (1 << 7) +-#define ADCFSM_STEPID 0x10 + ++/* Step Configuration */ ++#define STEPCONFIG_MODE_MASK (3 << 0) ++#define STEPCONFIG_MODE(val) (val << 0) ++#define STEPCONFIG_MODE_HWSYNC STEPCONFIG_MODE(2) ++#define STEPCONFIG_AVG_MASK (7 << 2) ++#define STEPCONFIG_AVG(val) (val << 2) ++#define STEPCONFIG_AVG_16 STEPCONFIG_AVG(4) ++#define STEPCONFIG_XPP BIT(5) ++#define STEPCONFIG_XNN BIT(6) ++#define STEPCONFIG_YPP BIT(7) ++#define STEPCONFIG_YNN BIT(8) ++#define STEPCONFIG_XNP BIT(9) ++#define STEPCONFIG_YPN BIT(10) ++#define STEPCONFIG_INM_MASK (0xF << 15) ++#define STEPCONFIG_INM(val) (val << 15) ++#define STEPCONFIG_INM_ADCREFM STEPCONFIG_INM(8) ++#define STEPCONFIG_INP_MASK (0xF << 19) ++#define STEPCONFIG_INP(val) (val << 19) ++#define STEPCONFIG_INP_AN2 STEPCONFIG_INP(2) ++#define STEPCONFIG_INP_AN3 STEPCONFIG_INP(3) ++#define STEPCONFIG_INP_AN4 STEPCONFIG_INP(4) ++#define STEPCONFIG_INP_ADCREFM STEPCONFIG_INP(8) ++#define STEPCONFIG_FIFO1 BIT(26) ++ ++/* Delay register */ ++#define STEPDELAY_OPEN_MASK (0x3FFFF << 0) ++#define STEPDELAY_OPEN(val) (val << 0) ++#define STEPCONFIG_OPENDLY STEPDELAY_OPEN(0x098) ++ ++/* Charge Config */ ++#define STEPCHARGE_RFP_MASK (7 << 12) ++#define STEPCHARGE_RFP(val) (val << 12) ++#define STEPCHARGE_RFP_XPUL STEPCHARGE_RFP(1) ++#define STEPCHARGE_INM_MASK (0xF << 15) ++#define STEPCHARGE_INM(val) (val << 15) ++#define STEPCHARGE_INM_AN1 STEPCHARGE_INM(1) ++#define STEPCHARGE_INP_MASK (0xF << 19) ++#define STEPCHARGE_INP(val) (val << 19) ++#define STEPCHARGE_INP_AN1 STEPCHARGE_INP(1) ++#define STEPCHARGE_RFM_MASK (3 << 23) ++#define STEPCHARGE_RFM(val) (val << 23) ++#define STEPCHARGE_RFM_XNUR STEPCHARGE_RFM(1) ++ ++/* Charge delay */ ++#define CHARGEDLY_OPEN_MASK (0x3FFFF << 0) ++#define CHARGEDLY_OPEN(val) (val << 0) ++#define CHARGEDLY_OPENDLY CHARGEDLY_OPEN(1) ++ ++/* Control register */ ++#define CNTRLREG_TSCSSENB BIT(0) ++#define CNTRLREG_STEPID BIT(1) ++#define CNTRLREG_STEPCONFIGWRT BIT(2) ++#define CNTRLREG_AFE_CTRL_MASK (3 << 5) ++#define CNTRLREG_AFE_CTRL(val) (val << 5) ++#define CNTRLREG_4WIRE CNTRLREG_AFE_CTRL(1) ++#define CNTRLREG_5WIRE CNTRLREG_AFE_CTRL(2) ++#define CNTRLREG_8WIRE CNTRLREG_AFE_CTRL(3) ++#define CNTRLREG_TSCENB BIT(7) ++ ++#define ADCFSM_STEPID 0x10 + #define SEQ_SETTLE 275 + #define ADC_CLK 3000000 + #define MAX_12BIT ((1 << 12) - 1) +-#define TSCADC_DELTA_X 15 +-#define TSCADC_DELTA_Y 15 + + struct tscadc { + struct input_dev *input; +@@ -119,18 +155,18 @@ static void tscadc_step_config(struct tscadc *ts_dev) + /* Configure the Step registers */ + + config = STEPCONFIG_MODE_HWSYNC | +- STEPCONFIG_SAMPLES_AVG | STEPCONFIG_XPP; ++ STEPCONFIG_AVG_16 | STEPCONFIG_XPP; + switch (ts_dev->wires) { + case 4: +- config |= STEPCONFIG_INP | STEPCONFIG_XNN; ++ config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; + break; + case 5: + config |= STEPCONFIG_YNN | +- STEPCONFIG_INP_5 | STEPCONFIG_XNN | ++ STEPCONFIG_INP_AN4 | STEPCONFIG_XNN | + STEPCONFIG_YPP; + break; + case 8: +- config |= STEPCONFIG_INP | STEPCONFIG_XNN; ++ config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; + break; + } + +@@ -141,14 +177,14 @@ static void tscadc_step_config(struct tscadc *ts_dev) + + config = 0; + config = STEPCONFIG_MODE_HWSYNC | +- STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YNN | +- STEPCONFIG_INM | STEPCONFIG_FIFO1; ++ STEPCONFIG_AVG_16 | STEPCONFIG_YNN | ++ STEPCONFIG_INM_ADCREFM | STEPCONFIG_FIFO1; + switch (ts_dev->wires) { + case 4: + config |= STEPCONFIG_YPP; + break; + case 5: +- config |= STEPCONFIG_XPP | STEPCONFIG_INP_5 | ++ config |= STEPCONFIG_XPP | STEPCONFIG_INP_AN4 | + STEPCONFIG_XNP | STEPCONFIG_YPN; + break; + case 8: +@@ -164,21 +200,21 @@ static void tscadc_step_config(struct tscadc *ts_dev) + config = 0; + /* Charge step configuration */ + config = STEPCONFIG_XPP | STEPCONFIG_YNN | +- STEPCHARGE_RFP | STEPCHARGE_RFM | +- STEPCHARGE_INM | STEPCHARGE_INP; ++ STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR | ++ STEPCHARGE_INM_AN1 | STEPCHARGE_INP_AN1; + + tscadc_writel(ts_dev, REG_CHARGECONFIG, config); +- tscadc_writel(ts_dev, REG_CHARGEDELAY, STEPCHARGE_DELAY); ++ tscadc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY); + + config = 0; + /* Configure to calculate pressure */ + config = STEPCONFIG_MODE_HWSYNC | +- STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YPP | +- STEPCONFIG_XNN | STEPCONFIG_INM; ++ STEPCONFIG_AVG_16 | STEPCONFIG_YPP | ++ STEPCONFIG_XNN | STEPCONFIG_INM_ADCREFM; + tscadc_writel(ts_dev, REG_STEPCONFIG13, config); + tscadc_writel(ts_dev, REG_STEPDELAY13, STEPCONFIG_OPENDLY); + +- config |= STEPCONFIG_Z1 | STEPCONFIG_FIFO1; ++ config |= STEPCONFIG_INP_AN3 | STEPCONFIG_FIFO1; + tscadc_writel(ts_dev, REG_STEPCONFIG14, config); + tscadc_writel(ts_dev, REG_STEPDELAY14, STEPCONFIG_OPENDLY); + +@@ -190,8 +226,8 @@ static void tscadc_idle_config(struct tscadc *ts_config) + unsigned int idleconfig; + + idleconfig = STEPCONFIG_YNN | +- STEPCONFIG_INM | +- STEPCONFIG_YPN | STEPIDLE_INP; ++ STEPCONFIG_INM_ADCREFM | ++ STEPCONFIG_YPN | STEPCONFIG_INP_ADCREFM; + tscadc_writel(ts_config, REG_IDLECONFIG, idleconfig); + } + diff --git a/patches/linux-3.7-rc6/0046-input-TSC-ti_tscadc-Add-Step-configuration-as-platfo.patch b/patches/linux-3.7-rc6/0046-input-TSC-ti_tscadc-Add-Step-configuration-as-platfo.patch new file mode 100644 index 0000000..bf40198 --- /dev/null +++ b/patches/linux-3.7-rc6/0046-input-TSC-ti_tscadc-Add-Step-configuration-as-platfo.patch @@ -0,0 +1,138 @@ +From b932cb2194e4e7ffc21e5c19b56d2b018ef88f5a Mon Sep 17 00:00:00 2001 +From: "Patil, Rachna" <rachna@ti.com> +Date: Tue, 16 Oct 2012 07:25:39 +0000 +Subject: [PATCH] input: TSC: ti_tscadc: Add Step configuration as platform + data + +There are 16 programmable Step Configuration +registers which are used by the sequencer. +Program the Steps in order to configure a channel +input to be sampled. If the same step is applied +several times, the coordinate values read are more +accurate. +Hence we provide the user an option of how many steps +should be configured. + +For ex: If this value is assigned as 4, This means that +4 steps are applied to read x co-ordinate and 4 steps to read +y co-ordinate. Furtheron the interrupt handler already +holds code to use delta filter and report the best value +out of these values to the input sub-system. + +Signed-off-by: Patil, Rachna <rachna@ti.com> +--- + drivers/input/touchscreen/ti_tscadc.c | 25 +++++++++++++------------ + include/linux/input/ti_tscadc.h | 6 ++++++ + 2 files changed, 19 insertions(+), 12 deletions(-) + +diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c +index d198cab..c1bd8e5 100644 +--- a/drivers/input/touchscreen/ti_tscadc.c ++++ b/drivers/input/touchscreen/ti_tscadc.c +@@ -41,10 +41,6 @@ + #define REG_CHARGEDELAY 0x060 + #define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8)) + #define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8)) +-#define REG_STEPCONFIG13 0x0C4 +-#define REG_STEPDELAY13 0x0C8 +-#define REG_STEPCONFIG14 0x0CC +-#define REG_STEPDELAY14 0x0D0 + #define REG_FIFO0CNT 0xE4 + #define REG_FIFO1THR 0xF4 + #define REG_FIFO0 0x100 +@@ -134,6 +130,7 @@ struct tscadc { + unsigned int wires; + unsigned int x_plate_resistance; + bool pen_down; ++ int steps_to_configure; + }; + + static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg) +@@ -150,9 +147,10 @@ static void tscadc_writel(struct tscadc *tsc, unsigned int reg, + static void tscadc_step_config(struct tscadc *ts_dev) + { + unsigned int config; +- int i; ++ int i, total_steps; + + /* Configure the Step registers */ ++ total_steps = 2 * ts_dev->steps_to_configure; + + config = STEPCONFIG_MODE_HWSYNC | + STEPCONFIG_AVG_16 | STEPCONFIG_XPP; +@@ -170,7 +168,7 @@ static void tscadc_step_config(struct tscadc *ts_dev) + break; + } + +- for (i = 1; i < 7; i++) { ++ for (i = 1; i <= ts_dev->steps_to_configure; i++) { + tscadc_writel(ts_dev, REG_STEPCONFIG(i), config); + tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); + } +@@ -192,7 +190,7 @@ static void tscadc_step_config(struct tscadc *ts_dev) + break; + } + +- for (i = 7; i < 13; i++) { ++ for (i = (ts_dev->steps_to_configure + 1); i <= total_steps; i++) { + tscadc_writel(ts_dev, REG_STEPCONFIG(i), config); + tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); + } +@@ -211,12 +209,14 @@ static void tscadc_step_config(struct tscadc *ts_dev) + config = STEPCONFIG_MODE_HWSYNC | + STEPCONFIG_AVG_16 | STEPCONFIG_YPP | + STEPCONFIG_XNN | STEPCONFIG_INM_ADCREFM; +- tscadc_writel(ts_dev, REG_STEPCONFIG13, config); +- tscadc_writel(ts_dev, REG_STEPDELAY13, STEPCONFIG_OPENDLY); ++ tscadc_writel(ts_dev, REG_STEPCONFIG(total_steps + 1), config); ++ tscadc_writel(ts_dev, REG_STEPDELAY(total_steps + 1), ++ STEPCONFIG_OPENDLY); + + config |= STEPCONFIG_INP_AN3 | STEPCONFIG_FIFO1; +- tscadc_writel(ts_dev, REG_STEPCONFIG14, config); +- tscadc_writel(ts_dev, REG_STEPDELAY14, STEPCONFIG_OPENDLY); ++ tscadc_writel(ts_dev, REG_STEPCONFIG(total_steps + 2), config); ++ tscadc_writel(ts_dev, REG_STEPDELAY(total_steps + 2), ++ STEPCONFIG_OPENDLY); + + tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB); + } +@@ -379,6 +379,7 @@ static int __devinit tscadc_probe(struct platform_device *pdev) + ts_dev->irq = irq; + ts_dev->wires = pdata->wires; + ts_dev->x_plate_resistance = pdata->x_plate_resistance; ++ ts_dev->steps_to_configure = pdata->steps_to_configure; + + res = request_mem_region(res->start, resource_size(res), pdev->name); + if (!res) { +@@ -447,7 +448,7 @@ static int __devinit tscadc_probe(struct platform_device *pdev) + tscadc_idle_config(ts_dev); + tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO1THRES); + tscadc_step_config(ts_dev); +- tscadc_writel(ts_dev, REG_FIFO1THR, 6); ++ tscadc_writel(ts_dev, REG_FIFO1THR, ts_dev->steps_to_configure); + + ctrl |= CNTRLREG_TSCSSENB; + tscadc_writel(ts_dev, REG_CTRL, ctrl); +diff --git a/include/linux/input/ti_tscadc.h b/include/linux/input/ti_tscadc.h +index b10a527..ad442a3 100644 +--- a/include/linux/input/ti_tscadc.h ++++ b/include/linux/input/ti_tscadc.h +@@ -7,11 +7,17 @@ + * i.e. 4/5/8 wire touchscreen support + * on the platform. + * @x_plate_resistance: X plate resistance. ++ * @steps_to_configure: The sequencer supports a total of ++ * 16 programmable steps. ++ * A step configured to read a single ++ * co-ordinate value, can be applied ++ * more number of times for better results. + */ + + struct tsc_data { + int wires; + int x_plate_resistance; ++ int steps_to_configure; + }; + + #endif diff --git a/patches/linux-3.7-rc6/0047-input-TSC-ti_tscadc-set-FIFO0-threshold-Interrupt.patch b/patches/linux-3.7-rc6/0047-input-TSC-ti_tscadc-set-FIFO0-threshold-Interrupt.patch new file mode 100644 index 0000000..e61ea48 --- /dev/null +++ b/patches/linux-3.7-rc6/0047-input-TSC-ti_tscadc-set-FIFO0-threshold-Interrupt.patch @@ -0,0 +1,67 @@ +From ac7eef064eb1619eaf030e9f36e784230a8d7baa Mon Sep 17 00:00:00 2001 +From: "Patil, Rachna" <rachna@ti.com> +Date: Tue, 16 Oct 2012 07:25:40 +0000 +Subject: [PATCH] input: TSC: ti_tscadc: set FIFO0 threshold Interrupt + +Code currently uses FIFO1 threshold interrupt. +since this is a MFD, Dedicating FIFO0 to touchscreen +and making way for other devices to use FIFO1 as well. +The FIFO can be shared between 2 devices but since the +interrupt used is threshold interrupt on FIFO1, we would +end up having wrong interrupts. Hence changing the same. + +Signed-off-by: Patil, Rachna <rachna@ti.com> +--- + drivers/input/touchscreen/ti_tscadc.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c +index c1bd8e5..2cc19b0 100644 +--- a/drivers/input/touchscreen/ti_tscadc.c ++++ b/drivers/input/touchscreen/ti_tscadc.c +@@ -42,6 +42,7 @@ + #define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8)) + #define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8)) + #define REG_FIFO0CNT 0xE4 ++#define REG_FIFO0THR 0xE8 + #define REG_FIFO1THR 0xF4 + #define REG_FIFO0 0x100 + #define REG_FIFO1 0x200 +@@ -55,6 +56,7 @@ + #define STPENB_STEPENB STEPENB(0x7FFF) + + /* IRQ enable */ ++#define IRQENB_FIFO0THRES BIT(2) + #define IRQENB_FIFO1THRES BIT(5) + #define IRQENB_PENUP BIT(9) + +@@ -277,7 +279,7 @@ static irqreturn_t tscadc_irq(int irq, void *dev) + unsigned int fsm; + + status = tscadc_readl(ts_dev, REG_IRQSTATUS); +- if (status & IRQENB_FIFO1THRES) { ++ if (status & IRQENB_FIFO0THRES) { + tscadc_read_coordinates(ts_dev, &x, &y); + + z1 = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff; +@@ -303,7 +305,7 @@ static irqreturn_t tscadc_irq(int irq, void *dev) + input_sync(input_dev); + } + } +- irqclr |= IRQENB_FIFO1THRES; ++ irqclr |= IRQENB_FIFO0THRES; + } + + /* +@@ -446,9 +448,9 @@ static int __devinit tscadc_probe(struct platform_device *pdev) + tscadc_writel(ts_dev, REG_CTRL, ctrl); + + tscadc_idle_config(ts_dev); +- tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO1THRES); ++ tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); + tscadc_step_config(ts_dev); +- tscadc_writel(ts_dev, REG_FIFO1THR, ts_dev->steps_to_configure); ++ tscadc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure); + + ctrl |= CNTRLREG_TSCSSENB; + tscadc_writel(ts_dev, REG_CTRL, ctrl); diff --git a/patches/linux-3.7-rc6/0048-input-TSC-ti_tscadc-Remove-definition-of-End-Of-Inte.patch b/patches/linux-3.7-rc6/0048-input-TSC-ti_tscadc-Remove-definition-of-End-Of-Inte.patch new file mode 100644 index 0000000..ab04b48 --- /dev/null +++ b/patches/linux-3.7-rc6/0048-input-TSC-ti_tscadc-Remove-definition-of-End-Of-Inte.patch @@ -0,0 +1,37 @@ +From e1c5c484bc32790c868f8de1300780b950d4514d Mon Sep 17 00:00:00 2001 +From: "Patil, Rachna" <rachna@ti.com> +Date: Tue, 16 Oct 2012 07:25:41 +0000 +Subject: [PATCH] input: TSC: ti_tscadc: Remove definition of End Of Interrupt + register + +The touchscreen IP uses level sensitive interrupts rather +than edge sensitive interrupts and therefore the is no need +to use the EOI register to have the module re-strobe the +interrupt line if there pending interrupts exist. + +Signed-off-by: Patil, Rachna <rachna@ti.com> +--- + drivers/input/touchscreen/ti_tscadc.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c +index 2cc19b0..ec0a442 100644 +--- a/drivers/input/touchscreen/ti_tscadc.c ++++ b/drivers/input/touchscreen/ti_tscadc.c +@@ -27,7 +27,6 @@ + #include <linux/input/ti_tscadc.h> + #include <linux/delay.h> + +-#define REG_IRQEOI 0x020 + #define REG_RAWIRQSTATUS 0x024 + #define REG_IRQSTATUS 0x028 + #define REG_IRQENABLE 0x02C +@@ -330,8 +329,6 @@ static irqreturn_t tscadc_irq(int irq, void *dev) + } + + tscadc_writel(ts_dev, REG_IRQSTATUS, irqclr); +- /* check pending interrupts */ +- tscadc_writel(ts_dev, REG_IRQEOI, 0x0); + + tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB); + return IRQ_HANDLED; diff --git a/patches/linux-3.7-rc6/0049-input-TSC-ti_tscadc-Rename-the-existing-touchscreen-.patch b/patches/linux-3.7-rc6/0049-input-TSC-ti_tscadc-Rename-the-existing-touchscreen-.patch new file mode 100644 index 0000000..0b482cd --- /dev/null +++ b/patches/linux-3.7-rc6/0049-input-TSC-ti_tscadc-Rename-the-existing-touchscreen-.patch @@ -0,0 +1,1174 @@ +From 0f0fedfede0d4c004f4612e4725b311b7bdcb061 Mon Sep 17 00:00:00 2001 +From: "Patil, Rachna" <rachna@ti.com> +Date: Tue, 16 Oct 2012 07:25:42 +0000 +Subject: [PATCH] input: TSC: ti_tscadc: Rename the existing touchscreen + driver + +Make way for addition of MFD driver. +The existing touchsreen driver is a MFD client. +For better readability we rename the file to +indicate its functionality as only touchscreen. + +Signed-off-by: Patil, Rachna <rachna@ti.com> +--- + drivers/input/touchscreen/Kconfig | 4 +- + drivers/input/touchscreen/Makefile | 2 +- + drivers/input/touchscreen/ti_am335x_tsc.c | 522 +++++++++++++++++++++++++++++ + drivers/input/touchscreen/ti_tscadc.c | 522 ----------------------------- + include/linux/input/ti_am335x_tsc.h | 23 ++ + include/linux/input/ti_tscadc.h | 23 -- + 6 files changed, 548 insertions(+), 548 deletions(-) + create mode 100644 drivers/input/touchscreen/ti_am335x_tsc.c + delete mode 100644 drivers/input/touchscreen/ti_tscadc.c + create mode 100644 include/linux/input/ti_am335x_tsc.h + delete mode 100644 include/linux/input/ti_tscadc.h + +diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig +index f7668b2..d31dc5f 100644 +--- a/drivers/input/touchscreen/Kconfig ++++ b/drivers/input/touchscreen/Kconfig +@@ -529,7 +529,7 @@ config TOUCHSCREEN_TOUCHWIN + To compile this driver as a module, choose M here: the + module will be called touchwin. + +-config TOUCHSCREEN_TI_TSCADC ++config TOUCHSCREEN_TI_AM335X_TSC + tristate "TI Touchscreen Interface" + depends on ARCH_OMAP2PLUS + help +@@ -539,7 +539,7 @@ config TOUCHSCREEN_TI_TSCADC + If unsure, say N. + + To compile this driver as a module, choose M here: the +- module will be called ti_tscadc. ++ module will be called ti_am335x_tsc. + + config TOUCHSCREEN_ATMEL_TSADCC + tristate "Atmel Touchscreen Interface" +diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile +index 178eb12..7c4c78e 100644 +--- a/drivers/input/touchscreen/Makefile ++++ b/drivers/input/touchscreen/Makefile +@@ -52,7 +52,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o + obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o + obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o + obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o +-obj-$(CONFIG_TOUCHSCREEN_TI_TSCADC) += ti_tscadc.o ++obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o + obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o + obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o + obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o +diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c +new file mode 100644 +index 0000000..462950a +--- /dev/null ++++ b/drivers/input/touchscreen/ti_am335x_tsc.c +@@ -0,0 +1,522 @@ ++/* ++ * TI Touch Screen driver ++ * ++ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation version 2. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++ ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/err.h> ++#include <linux/module.h> ++#include <linux/input.h> ++#include <linux/slab.h> ++#include <linux/interrupt.h> ++#include <linux/clk.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/input/ti_am335x_tsc.h> ++#include <linux/delay.h> ++ ++#define REG_RAWIRQSTATUS 0x024 ++#define REG_IRQSTATUS 0x028 ++#define REG_IRQENABLE 0x02C ++#define REG_IRQWAKEUP 0x034 ++#define REG_CTRL 0x040 ++#define REG_ADCFSM 0x044 ++#define REG_CLKDIV 0x04C ++#define REG_SE 0x054 ++#define REG_IDLECONFIG 0x058 ++#define REG_CHARGECONFIG 0x05C ++#define REG_CHARGEDELAY 0x060 ++#define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8)) ++#define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8)) ++#define REG_FIFO0CNT 0xE4 ++#define REG_FIFO0THR 0xE8 ++#define REG_FIFO1THR 0xF4 ++#define REG_FIFO0 0x100 ++#define REG_FIFO1 0x200 ++ ++/* Register Bitfields */ ++#define IRQWKUP_ENB BIT(0) ++ ++/* Step Enable */ ++#define STEPENB_MASK (0x1FFFF << 0) ++#define STEPENB(val) (val << 0) ++#define STPENB_STEPENB STEPENB(0x7FFF) ++ ++/* IRQ enable */ ++#define IRQENB_FIFO0THRES BIT(2) ++#define IRQENB_FIFO1THRES BIT(5) ++#define IRQENB_PENUP BIT(9) ++ ++/* Step Configuration */ ++#define STEPCONFIG_MODE_MASK (3 << 0) ++#define STEPCONFIG_MODE(val) (val << 0) ++#define STEPCONFIG_MODE_HWSYNC STEPCONFIG_MODE(2) ++#define STEPCONFIG_AVG_MASK (7 << 2) ++#define STEPCONFIG_AVG(val) (val << 2) ++#define STEPCONFIG_AVG_16 STEPCONFIG_AVG(4) ++#define STEPCONFIG_XPP BIT(5) ++#define STEPCONFIG_XNN BIT(6) ++#define STEPCONFIG_YPP BIT(7) ++#define STEPCONFIG_YNN BIT(8) ++#define STEPCONFIG_XNP BIT(9) ++#define STEPCONFIG_YPN BIT(10) ++#define STEPCONFIG_INM_MASK (0xF << 15) ++#define STEPCONFIG_INM(val) (val << 15) ++#define STEPCONFIG_INM_ADCREFM STEPCONFIG_INM(8) ++#define STEPCONFIG_INP_MASK (0xF << 19) ++#define STEPCONFIG_INP(val) (val << 19) ++#define STEPCONFIG_INP_AN2 STEPCONFIG_INP(2) ++#define STEPCONFIG_INP_AN3 STEPCONFIG_INP(3) ++#define STEPCONFIG_INP_AN4 STEPCONFIG_INP(4) ++#define STEPCONFIG_INP_ADCREFM STEPCONFIG_INP(8) ++#define STEPCONFIG_FIFO1 BIT(26) ++ ++/* Delay register */ ++#define STEPDELAY_OPEN_MASK (0x3FFFF << 0) ++#define STEPDELAY_OPEN(val) (val << 0) ++#define STEPCONFIG_OPENDLY STEPDELAY_OPEN(0x098) ++ ++/* Charge Config */ ++#define STEPCHARGE_RFP_MASK (7 << 12) ++#define STEPCHARGE_RFP(val) (val << 12) ++#define STEPCHARGE_RFP_XPUL STEPCHARGE_RFP(1) ++#define STEPCHARGE_INM_MASK (0xF << 15) ++#define STEPCHARGE_INM(val) (val << 15) ++#define STEPCHARGE_INM_AN1 STEPCHARGE_INM(1) ++#define STEPCHARGE_INP_MASK (0xF << 19) ++#define STEPCHARGE_INP(val) (val << 19) ++#define STEPCHARGE_INP_AN1 STEPCHARGE_INP(1) ++#define STEPCHARGE_RFM_MASK (3 << 23) ++#define STEPCHARGE_RFM(val) (val << 23) ++#define STEPCHARGE_RFM_XNUR STEPCHARGE_RFM(1) ++ ++/* Charge delay */ ++#define CHARGEDLY_OPEN_MASK (0x3FFFF << 0) ++#define CHARGEDLY_OPEN(val) (val << 0) ++#define CHARGEDLY_OPENDLY CHARGEDLY_OPEN(1) ++ ++/* Control register */ ++#define CNTRLREG_TSCSSENB BIT(0) ++#define CNTRLREG_STEPID BIT(1) ++#define CNTRLREG_STEPCONFIGWRT BIT(2) ++#define CNTRLREG_AFE_CTRL_MASK (3 << 5) ++#define CNTRLREG_AFE_CTRL(val) (val << 5) ++#define CNTRLREG_4WIRE CNTRLREG_AFE_CTRL(1) ++#define CNTRLREG_5WIRE CNTRLREG_AFE_CTRL(2) ++#define CNTRLREG_8WIRE CNTRLREG_AFE_CTRL(3) ++#define CNTRLREG_TSCENB BIT(7) ++ ++#define ADCFSM_STEPID 0x10 ++#define SEQ_SETTLE 275 ++#define ADC_CLK 3000000 ++#define MAX_12BIT ((1 << 12) - 1) ++ ++struct titsc { ++ struct input_dev *input; ++ struct clk *tsc_ick; ++ void __iomem *tsc_base; ++ unsigned int irq; ++ unsigned int wires; ++ unsigned int x_plate_resistance; ++ bool pen_down; ++ int steps_to_configure; ++}; ++ ++static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) ++{ ++ return readl(ts->tsc_base + reg); ++} ++ ++static void titsc_writel(struct titsc *tsc, unsigned int reg, ++ unsigned int val) ++{ ++ writel(val, tsc->tsc_base + reg); ++} ++ ++static void titsc_step_config(struct titsc *ts_dev) ++{ ++ unsigned int config; ++ int i, total_steps; ++ ++ /* Configure the Step registers */ ++ total_steps = 2 * ts_dev->steps_to_configure; ++ ++ config = STEPCONFIG_MODE_HWSYNC | ++ STEPCONFIG_AVG_16 | STEPCONFIG_XPP; ++ switch (ts_dev->wires) { ++ case 4: ++ config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; ++ break; ++ case 5: ++ config |= STEPCONFIG_YNN | ++ STEPCONFIG_INP_AN4 | STEPCONFIG_XNN | ++ STEPCONFIG_YPP; ++ break; ++ case 8: ++ config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; ++ break; ++ } ++ ++ for (i = 1; i <= ts_dev->steps_to_configure; i++) { ++ titsc_writel(ts_dev, REG_STEPCONFIG(i), config); ++ titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); ++ } ++ ++ config = 0; ++ config = STEPCONFIG_MODE_HWSYNC | ++ STEPCONFIG_AVG_16 | STEPCONFIG_YNN | ++ STEPCONFIG_INM_ADCREFM | STEPCONFIG_FIFO1; ++ switch (ts_dev->wires) { ++ case 4: ++ config |= STEPCONFIG_YPP; ++ break; ++ case 5: ++ config |= STEPCONFIG_XPP | STEPCONFIG_INP_AN4 | ++ STEPCONFIG_XNP | STEPCONFIG_YPN; ++ break; ++ case 8: ++ config |= STEPCONFIG_YPP; ++ break; ++ } ++ ++ for (i = (ts_dev->steps_to_configure + 1); i <= total_steps; i++) { ++ titsc_writel(ts_dev, REG_STEPCONFIG(i), config); ++ titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); ++ } ++ ++ config = 0; ++ /* Charge step configuration */ ++ config = STEPCONFIG_XPP | STEPCONFIG_YNN | ++ STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR | ++ STEPCHARGE_INM_AN1 | STEPCHARGE_INP_AN1; ++ ++ titsc_writel(ts_dev, REG_CHARGECONFIG, config); ++ titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY); ++ ++ config = 0; ++ /* Configure to calculate pressure */ ++ config = STEPCONFIG_MODE_HWSYNC | ++ STEPCONFIG_AVG_16 | STEPCONFIG_YPP | ++ STEPCONFIG_XNN | STEPCONFIG_INM_ADCREFM; ++ titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 1), config); ++ titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 1), ++ STEPCONFIG_OPENDLY); ++ ++ config |= STEPCONFIG_INP_AN3 | STEPCONFIG_FIFO1; ++ titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 2), config); ++ titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2), ++ STEPCONFIG_OPENDLY); ++ ++ titsc_writel(ts_dev, REG_SE, STPENB_STEPENB); ++} ++ ++static void titsc_idle_config(struct titsc *ts_config) ++{ ++ unsigned int idleconfig; ++ ++ idleconfig = STEPCONFIG_YNN | ++ STEPCONFIG_INM_ADCREFM | ++ STEPCONFIG_YPN | STEPCONFIG_INP_ADCREFM; ++ titsc_writel(ts_config, REG_IDLECONFIG, idleconfig); ++} ++ ++static void titsc_read_coordinates(struct titsc *ts_dev, ++ unsigned int *x, unsigned int *y) ++{ ++ unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT); ++ unsigned int prev_val_x = ~0, prev_val_y = ~0; ++ unsigned int prev_diff_x = ~0, prev_diff_y = ~0; ++ unsigned int read, diff; ++ unsigned int i; ++ ++ /* ++ * Delta filter is used to remove large variations in sampled ++ * values from ADC. The filter tries to predict where the next ++ * coordinate could be. This is done by taking a previous ++ * coordinate and subtracting it form current one. Further the ++ * algorithm compares the difference with that of a present value, ++ * if true the value is reported to the sub system. ++ */ ++ for (i = 0; i < fifocount - 1; i++) { ++ read = titsc_readl(ts_dev, REG_FIFO0) & 0xfff; ++ diff = abs(read - prev_val_x); ++ if (diff < prev_diff_x) { ++ prev_diff_x = diff; ++ *x = read; ++ } ++ prev_val_x = read; ++ ++ read = titsc_readl(ts_dev, REG_FIFO1) & 0xfff; ++ diff = abs(read - prev_val_y); ++ if (diff < prev_diff_y) { ++ prev_diff_y = diff; ++ *y = read; ++ } ++ prev_val_y = read; ++ } ++} ++ ++static irqreturn_t titsc_irq(int irq, void *dev) ++{ ++ struct titsc *ts_dev = dev; ++ struct input_dev *input_dev = ts_dev->input; ++ unsigned int status, irqclr = 0; ++ unsigned int x = 0, y = 0; ++ unsigned int z1, z2, z; ++ unsigned int fsm; ++ ++ status = titsc_readl(ts_dev, REG_IRQSTATUS); ++ if (status & IRQENB_FIFO0THRES) { ++ titsc_read_coordinates(ts_dev, &x, &y); ++ ++ z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff; ++ z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff; ++ ++ if (ts_dev->pen_down && z1 != 0 && z2 != 0) { ++ /* ++ * Calculate pressure using formula ++ * Resistance(touch) = x plate resistance * ++ * x postion/4096 * ((z2 / z1) - 1) ++ */ ++ z = z2 - z1; ++ z *= x; ++ z *= ts_dev->x_plate_resistance; ++ z /= z1; ++ z = (z + 2047) >> 12; ++ ++ if (z <= MAX_12BIT) { ++ input_report_abs(input_dev, ABS_X, x); ++ input_report_abs(input_dev, ABS_Y, y); ++ input_report_abs(input_dev, ABS_PRESSURE, z); ++ input_report_key(input_dev, BTN_TOUCH, 1); ++ input_sync(input_dev); ++ } ++ } ++ irqclr |= IRQENB_FIFO0THRES; ++ } ++ ++ /* ++ * Time for sequencer to settle, to read ++ * correct state of the sequencer. ++ */ ++ udelay(SEQ_SETTLE); ++ ++ status = titsc_readl(ts_dev, REG_RAWIRQSTATUS); ++ if (status & IRQENB_PENUP) { ++ /* Pen up event */ ++ fsm = titsc_readl(ts_dev, REG_ADCFSM); ++ if (fsm == ADCFSM_STEPID) { ++ ts_dev->pen_down = false; ++ input_report_key(input_dev, BTN_TOUCH, 0); ++ input_report_abs(input_dev, ABS_PRESSURE, 0); ++ input_sync(input_dev); ++ } else { ++ ts_dev->pen_down = true; ++ } ++ irqclr |= IRQENB_PENUP; ++ } ++ ++ titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); ++ ++ titsc_writel(ts_dev, REG_SE, STPENB_STEPENB); ++ return IRQ_HANDLED; ++} ++ ++/* ++ * The functions for inserting/removing driver as a module. ++ */ ++ ++static int __devinit titsc_probe(struct platform_device *pdev) ++{ ++ const struct tsc_data *pdata = pdev->dev.platform_data; ++ struct resource *res; ++ struct titsc *ts_dev; ++ struct input_dev *input_dev; ++ struct clk *clk; ++ int err; ++ int clk_value, ctrl, irq; ++ ++ if (!pdata) { ++ dev_err(&pdev->dev, "missing platform data.\n"); ++ return -EINVAL; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "no memory resource defined.\n"); ++ return -EINVAL; ++ } ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(&pdev->dev, "no irq ID is specified.\n"); ++ return -EINVAL; ++ } ++ ++ /* Allocate memory for device */ ++ ts_dev = kzalloc(sizeof(struct titsc), GFP_KERNEL); ++ input_dev = input_allocate_device(); ++ if (!ts_dev || !input_dev) { ++ dev_err(&pdev->dev, "failed to allocate memory.\n"); ++ err = -ENOMEM; ++ goto err_free_mem; ++ } ++ ++ ts_dev->input = input_dev; ++ ts_dev->irq = irq; ++ ts_dev->wires = pdata->wires; ++ ts_dev->x_plate_resistance = pdata->x_plate_resistance; ++ ts_dev->steps_to_configure = pdata->steps_to_configure; ++ ++ res = request_mem_region(res->start, resource_size(res), pdev->name); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to reserve registers.\n"); ++ err = -EBUSY; ++ goto err_free_mem; ++ } ++ ++ ts_dev->tsc_base = ioremap(res->start, resource_size(res)); ++ if (!ts_dev->tsc_base) { ++ dev_err(&pdev->dev, "failed to map registers.\n"); ++ err = -ENOMEM; ++ goto err_release_mem_region; ++ } ++ ++ err = request_irq(ts_dev->irq, titsc_irq, ++ 0, pdev->dev.driver->name, ts_dev); ++ if (err) { ++ dev_err(&pdev->dev, "failed to allocate irq.\n"); ++ goto err_unmap_regs; ++ } ++ ++ ts_dev->tsc_ick = clk_get(&pdev->dev, "adc_tsc_ick"); ++ if (IS_ERR(ts_dev->tsc_ick)) { ++ dev_err(&pdev->dev, "failed to get TSC ick\n"); ++ goto err_free_irq; ++ } ++ clk_enable(ts_dev->tsc_ick); ++ ++ clk = clk_get(&pdev->dev, "adc_tsc_fck"); ++ if (IS_ERR(clk)) { ++ dev_err(&pdev->dev, "failed to get TSC fck\n"); ++ err = PTR_ERR(clk); ++ goto err_disable_clk; ++ } ++ ++ clk_value = clk_get_rate(clk) / ADC_CLK; ++ clk_put(clk); ++ ++ if (clk_value < 7) { ++ dev_err(&pdev->dev, "clock input less than min clock requirement\n"); ++ goto err_disable_clk; ++ } ++ /* CLKDIV needs to be configured to the value minus 1 */ ++ titsc_writel(ts_dev, REG_CLKDIV, clk_value - 1); ++ ++ /* Enable wake-up of the SoC using touchscreen */ ++ titsc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); ++ ++ ctrl = CNTRLREG_STEPCONFIGWRT | ++ CNTRLREG_TSCENB | ++ CNTRLREG_STEPID; ++ switch (ts_dev->wires) { ++ case 4: ++ ctrl |= CNTRLREG_4WIRE; ++ break; ++ case 5: ++ ctrl |= CNTRLREG_5WIRE; ++ break; ++ case 8: ++ ctrl |= CNTRLREG_8WIRE; ++ break; ++ } ++ titsc_writel(ts_dev, REG_CTRL, ctrl); ++ ++ titsc_idle_config(ts_dev); ++ titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); ++ titsc_step_config(ts_dev); ++ titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure); ++ ++ ctrl |= CNTRLREG_TSCSSENB; ++ titsc_writel(ts_dev, REG_CTRL, ctrl); ++ ++ input_dev->name = "ti-tsc-adc"; ++ input_dev->dev.parent = &pdev->dev; ++ ++ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); ++ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); ++ ++ input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); ++ ++ /* register to the input system */ ++ err = input_register_device(input_dev); ++ if (err) ++ goto err_disable_clk; ++ ++ platform_set_drvdata(pdev, ts_dev); ++ return 0; ++ ++err_disable_clk: ++ clk_disable(ts_dev->tsc_ick); ++ clk_put(ts_dev->tsc_ick); ++err_free_irq: ++ free_irq(ts_dev->irq, ts_dev); ++err_unmap_regs: ++ iounmap(ts_dev->tsc_base); ++err_release_mem_region: ++ release_mem_region(res->start, resource_size(res)); ++err_free_mem: ++ input_free_device(input_dev); ++ kfree(ts_dev); ++ return err; ++} ++ ++static int __devexit titsc_remove(struct platform_device *pdev) ++{ ++ struct titsc *ts_dev = platform_get_drvdata(pdev); ++ struct resource *res; ++ ++ free_irq(ts_dev->irq, ts_dev); ++ ++ input_unregister_device(ts_dev->input); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ iounmap(ts_dev->tsc_base); ++ release_mem_region(res->start, resource_size(res)); ++ ++ clk_disable(ts_dev->tsc_ick); ++ clk_put(ts_dev->tsc_ick); ++ ++ kfree(ts_dev); ++ ++ platform_set_drvdata(pdev, NULL); ++ return 0; ++} ++ ++static struct platform_driver ti_tsc_driver = { ++ .probe = titsc_probe, ++ .remove = __devexit_p(titsc_remove), ++ .driver = { ++ .name = "tsc", ++ .owner = THIS_MODULE, ++ }, ++}; ++module_platform_driver(ti_tsc_driver); ++ ++MODULE_DESCRIPTION("TI touchscreen controller driver"); ++MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c +deleted file mode 100644 +index ec0a442..0000000 +--- a/drivers/input/touchscreen/ti_tscadc.c ++++ /dev/null +@@ -1,522 +0,0 @@ +-/* +- * TI Touch Screen driver +- * +- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License as +- * published by the Free Software Foundation version 2. +- * +- * This program is distributed "as is" WITHOUT ANY WARRANTY of any +- * kind, whether express or implied; without even the implied warranty +- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- */ +- +- +-#include <linux/init.h> +-#include <linux/kernel.h> +-#include <linux/err.h> +-#include <linux/module.h> +-#include <linux/input.h> +-#include <linux/slab.h> +-#include <linux/interrupt.h> +-#include <linux/clk.h> +-#include <linux/platform_device.h> +-#include <linux/io.h> +-#include <linux/input/ti_tscadc.h> +-#include <linux/delay.h> +- +-#define REG_RAWIRQSTATUS 0x024 +-#define REG_IRQSTATUS 0x028 +-#define REG_IRQENABLE 0x02C +-#define REG_IRQWAKEUP 0x034 +-#define REG_CTRL 0x040 +-#define REG_ADCFSM 0x044 +-#define REG_CLKDIV 0x04C +-#define REG_SE 0x054 +-#define REG_IDLECONFIG 0x058 +-#define REG_CHARGECONFIG 0x05C +-#define REG_CHARGEDELAY 0x060 +-#define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8)) +-#define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8)) +-#define REG_FIFO0CNT 0xE4 +-#define REG_FIFO0THR 0xE8 +-#define REG_FIFO1THR 0xF4 +-#define REG_FIFO0 0x100 +-#define REG_FIFO1 0x200 +- +-/* Register Bitfields */ +-#define IRQWKUP_ENB BIT(0) +- +-/* Step Enable */ +-#define STEPENB_MASK (0x1FFFF << 0) +-#define STEPENB(val) (val << 0) +-#define STPENB_STEPENB STEPENB(0x7FFF) +- +-/* IRQ enable */ +-#define IRQENB_FIFO0THRES BIT(2) +-#define IRQENB_FIFO1THRES BIT(5) +-#define IRQENB_PENUP BIT(9) +- +-/* Step Configuration */ +-#define STEPCONFIG_MODE_MASK (3 << 0) +-#define STEPCONFIG_MODE(val) (val << 0) +-#define STEPCONFIG_MODE_HWSYNC STEPCONFIG_MODE(2) +-#define STEPCONFIG_AVG_MASK (7 << 2) +-#define STEPCONFIG_AVG(val) (val << 2) +-#define STEPCONFIG_AVG_16 STEPCONFIG_AVG(4) +-#define STEPCONFIG_XPP BIT(5) +-#define STEPCONFIG_XNN BIT(6) +-#define STEPCONFIG_YPP BIT(7) +-#define STEPCONFIG_YNN BIT(8) +-#define STEPCONFIG_XNP BIT(9) +-#define STEPCONFIG_YPN BIT(10) +-#define STEPCONFIG_INM_MASK (0xF << 15) +-#define STEPCONFIG_INM(val) (val << 15) +-#define STEPCONFIG_INM_ADCREFM STEPCONFIG_INM(8) +-#define STEPCONFIG_INP_MASK (0xF << 19) +-#define STEPCONFIG_INP(val) (val << 19) +-#define STEPCONFIG_INP_AN2 STEPCONFIG_INP(2) +-#define STEPCONFIG_INP_AN3 STEPCONFIG_INP(3) +-#define STEPCONFIG_INP_AN4 STEPCONFIG_INP(4) +-#define STEPCONFIG_INP_ADCREFM STEPCONFIG_INP(8) +-#define STEPCONFIG_FIFO1 BIT(26) +- +-/* Delay register */ +-#define STEPDELAY_OPEN_MASK (0x3FFFF << 0) +-#define STEPDELAY_OPEN(val) (val << 0) +-#define STEPCONFIG_OPENDLY STEPDELAY_OPEN(0x098) +- +-/* Charge Config */ +-#define STEPCHARGE_RFP_MASK (7 << 12) +-#define STEPCHARGE_RFP(val) (val << 12) +-#define STEPCHARGE_RFP_XPUL STEPCHARGE_RFP(1) +-#define STEPCHARGE_INM_MASK (0xF << 15) +-#define STEPCHARGE_INM(val) (val << 15) +-#define STEPCHARGE_INM_AN1 STEPCHARGE_INM(1) +-#define STEPCHARGE_INP_MASK (0xF << 19) +-#define STEPCHARGE_INP(val) (val << 19) +-#define STEPCHARGE_INP_AN1 STEPCHARGE_INP(1) +-#define STEPCHARGE_RFM_MASK (3 << 23) +-#define STEPCHARGE_RFM(val) (val << 23) +-#define STEPCHARGE_RFM_XNUR STEPCHARGE_RFM(1) +- +-/* Charge delay */ +-#define CHARGEDLY_OPEN_MASK (0x3FFFF << 0) +-#define CHARGEDLY_OPEN(val) (val << 0) +-#define CHARGEDLY_OPENDLY CHARGEDLY_OPEN(1) +- +-/* Control register */ +-#define CNTRLREG_TSCSSENB BIT(0) +-#define CNTRLREG_STEPID BIT(1) +-#define CNTRLREG_STEPCONFIGWRT BIT(2) +-#define CNTRLREG_AFE_CTRL_MASK (3 << 5) +-#define CNTRLREG_AFE_CTRL(val) (val << 5) +-#define CNTRLREG_4WIRE CNTRLREG_AFE_CTRL(1) +-#define CNTRLREG_5WIRE CNTRLREG_AFE_CTRL(2) +-#define CNTRLREG_8WIRE CNTRLREG_AFE_CTRL(3) +-#define CNTRLREG_TSCENB BIT(7) +- +-#define ADCFSM_STEPID 0x10 +-#define SEQ_SETTLE 275 +-#define ADC_CLK 3000000 +-#define MAX_12BIT ((1 << 12) - 1) +- +-struct tscadc { +- struct input_dev *input; +- struct clk *tsc_ick; +- void __iomem *tsc_base; +- unsigned int irq; +- unsigned int wires; +- unsigned int x_plate_resistance; +- bool pen_down; +- int steps_to_configure; +-}; +- +-static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg) +-{ +- return readl(ts->tsc_base + reg); +-} +- +-static void tscadc_writel(struct tscadc *tsc, unsigned int reg, +- unsigned int val) +-{ +- writel(val, tsc->tsc_base + reg); +-} +- +-static void tscadc_step_config(struct tscadc *ts_dev) +-{ +- unsigned int config; +- int i, total_steps; +- +- /* Configure the Step registers */ +- total_steps = 2 * ts_dev->steps_to_configure; +- +- config = STEPCONFIG_MODE_HWSYNC | +- STEPCONFIG_AVG_16 | STEPCONFIG_XPP; +- switch (ts_dev->wires) { +- case 4: +- config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; +- break; +- case 5: +- config |= STEPCONFIG_YNN | +- STEPCONFIG_INP_AN4 | STEPCONFIG_XNN | +- STEPCONFIG_YPP; +- break; +- case 8: +- config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; +- break; +- } +- +- for (i = 1; i <= ts_dev->steps_to_configure; i++) { +- tscadc_writel(ts_dev, REG_STEPCONFIG(i), config); +- tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); +- } +- +- config = 0; +- config = STEPCONFIG_MODE_HWSYNC | +- STEPCONFIG_AVG_16 | STEPCONFIG_YNN | +- STEPCONFIG_INM_ADCREFM | STEPCONFIG_FIFO1; +- switch (ts_dev->wires) { +- case 4: +- config |= STEPCONFIG_YPP; +- break; +- case 5: +- config |= STEPCONFIG_XPP | STEPCONFIG_INP_AN4 | +- STEPCONFIG_XNP | STEPCONFIG_YPN; +- break; +- case 8: +- config |= STEPCONFIG_YPP; +- break; +- } +- +- for (i = (ts_dev->steps_to_configure + 1); i <= total_steps; i++) { +- tscadc_writel(ts_dev, REG_STEPCONFIG(i), config); +- tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); +- } +- +- config = 0; +- /* Charge step configuration */ +- config = STEPCONFIG_XPP | STEPCONFIG_YNN | +- STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR | +- STEPCHARGE_INM_AN1 | STEPCHARGE_INP_AN1; +- +- tscadc_writel(ts_dev, REG_CHARGECONFIG, config); +- tscadc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY); +- +- config = 0; +- /* Configure to calculate pressure */ +- config = STEPCONFIG_MODE_HWSYNC | +- STEPCONFIG_AVG_16 | STEPCONFIG_YPP | +- STEPCONFIG_XNN | STEPCONFIG_INM_ADCREFM; +- tscadc_writel(ts_dev, REG_STEPCONFIG(total_steps + 1), config); +- tscadc_writel(ts_dev, REG_STEPDELAY(total_steps + 1), +- STEPCONFIG_OPENDLY); +- +- config |= STEPCONFIG_INP_AN3 | STEPCONFIG_FIFO1; +- tscadc_writel(ts_dev, REG_STEPCONFIG(total_steps + 2), config); +- tscadc_writel(ts_dev, REG_STEPDELAY(total_steps + 2), +- STEPCONFIG_OPENDLY); +- +- tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB); +-} +- +-static void tscadc_idle_config(struct tscadc *ts_config) +-{ +- unsigned int idleconfig; +- +- idleconfig = STEPCONFIG_YNN | +- STEPCONFIG_INM_ADCREFM | +- STEPCONFIG_YPN | STEPCONFIG_INP_ADCREFM; +- tscadc_writel(ts_config, REG_IDLECONFIG, idleconfig); +-} +- +-static void tscadc_read_coordinates(struct tscadc *ts_dev, +- unsigned int *x, unsigned int *y) +-{ +- unsigned int fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT); +- unsigned int prev_val_x = ~0, prev_val_y = ~0; +- unsigned int prev_diff_x = ~0, prev_diff_y = ~0; +- unsigned int read, diff; +- unsigned int i; +- +- /* +- * Delta filter is used to remove large variations in sampled +- * values from ADC. The filter tries to predict where the next +- * coordinate could be. This is done by taking a previous +- * coordinate and subtracting it form current one. Further the +- * algorithm compares the difference with that of a present value, +- * if true the value is reported to the sub system. +- */ +- for (i = 0; i < fifocount - 1; i++) { +- read = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff; +- diff = abs(read - prev_val_x); +- if (diff < prev_diff_x) { +- prev_diff_x = diff; +- *x = read; +- } +- prev_val_x = read; +- +- read = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff; +- diff = abs(read - prev_val_y); +- if (diff < prev_diff_y) { +- prev_diff_y = diff; +- *y = read; +- } +- prev_val_y = read; +- } +-} +- +-static irqreturn_t tscadc_irq(int irq, void *dev) +-{ +- struct tscadc *ts_dev = dev; +- struct input_dev *input_dev = ts_dev->input; +- unsigned int status, irqclr = 0; +- unsigned int x = 0, y = 0; +- unsigned int z1, z2, z; +- unsigned int fsm; +- +- status = tscadc_readl(ts_dev, REG_IRQSTATUS); +- if (status & IRQENB_FIFO0THRES) { +- tscadc_read_coordinates(ts_dev, &x, &y); +- +- z1 = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff; +- z2 = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff; +- +- if (ts_dev->pen_down && z1 != 0 && z2 != 0) { +- /* +- * Calculate pressure using formula +- * Resistance(touch) = x plate resistance * +- * x postion/4096 * ((z2 / z1) - 1) +- */ +- z = z2 - z1; +- z *= x; +- z *= ts_dev->x_plate_resistance; +- z /= z1; +- z = (z + 2047) >> 12; +- +- if (z <= MAX_12BIT) { +- input_report_abs(input_dev, ABS_X, x); +- input_report_abs(input_dev, ABS_Y, y); +- input_report_abs(input_dev, ABS_PRESSURE, z); +- input_report_key(input_dev, BTN_TOUCH, 1); +- input_sync(input_dev); +- } +- } +- irqclr |= IRQENB_FIFO0THRES; +- } +- +- /* +- * Time for sequencer to settle, to read +- * correct state of the sequencer. +- */ +- udelay(SEQ_SETTLE); +- +- status = tscadc_readl(ts_dev, REG_RAWIRQSTATUS); +- if (status & IRQENB_PENUP) { +- /* Pen up event */ +- fsm = tscadc_readl(ts_dev, REG_ADCFSM); +- if (fsm == ADCFSM_STEPID) { +- ts_dev->pen_down = false; +- input_report_key(input_dev, BTN_TOUCH, 0); +- input_report_abs(input_dev, ABS_PRESSURE, 0); +- input_sync(input_dev); +- } else { +- ts_dev->pen_down = true; +- } +- irqclr |= IRQENB_PENUP; +- } +- +- tscadc_writel(ts_dev, REG_IRQSTATUS, irqclr); +- +- tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB); +- return IRQ_HANDLED; +-} +- +-/* +- * The functions for inserting/removing driver as a module. +- */ +- +-static int __devinit tscadc_probe(struct platform_device *pdev) +-{ +- const struct tsc_data *pdata = pdev->dev.platform_data; +- struct resource *res; +- struct tscadc *ts_dev; +- struct input_dev *input_dev; +- struct clk *clk; +- int err; +- int clk_value, ctrl, irq; +- +- if (!pdata) { +- dev_err(&pdev->dev, "missing platform data.\n"); +- return -EINVAL; +- } +- +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!res) { +- dev_err(&pdev->dev, "no memory resource defined.\n"); +- return -EINVAL; +- } +- +- irq = platform_get_irq(pdev, 0); +- if (irq < 0) { +- dev_err(&pdev->dev, "no irq ID is specified.\n"); +- return -EINVAL; +- } +- +- /* Allocate memory for device */ +- ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL); +- input_dev = input_allocate_device(); +- if (!ts_dev || !input_dev) { +- dev_err(&pdev->dev, "failed to allocate memory.\n"); +- err = -ENOMEM; +- goto err_free_mem; +- } +- +- ts_dev->input = input_dev; +- ts_dev->irq = irq; +- ts_dev->wires = pdata->wires; +- ts_dev->x_plate_resistance = pdata->x_plate_resistance; +- ts_dev->steps_to_configure = pdata->steps_to_configure; +- +- res = request_mem_region(res->start, resource_size(res), pdev->name); +- if (!res) { +- dev_err(&pdev->dev, "failed to reserve registers.\n"); +- err = -EBUSY; +- goto err_free_mem; +- } +- +- ts_dev->tsc_base = ioremap(res->start, resource_size(res)); +- if (!ts_dev->tsc_base) { +- dev_err(&pdev->dev, "failed to map registers.\n"); +- err = -ENOMEM; +- goto err_release_mem_region; +- } +- +- err = request_irq(ts_dev->irq, tscadc_irq, +- 0, pdev->dev.driver->name, ts_dev); +- if (err) { +- dev_err(&pdev->dev, "failed to allocate irq.\n"); +- goto err_unmap_regs; +- } +- +- ts_dev->tsc_ick = clk_get(&pdev->dev, "adc_tsc_ick"); +- if (IS_ERR(ts_dev->tsc_ick)) { +- dev_err(&pdev->dev, "failed to get TSC ick\n"); +- goto err_free_irq; +- } +- clk_enable(ts_dev->tsc_ick); +- +- clk = clk_get(&pdev->dev, "adc_tsc_fck"); +- if (IS_ERR(clk)) { +- dev_err(&pdev->dev, "failed to get TSC fck\n"); +- err = PTR_ERR(clk); +- goto err_disable_clk; +- } +- +- clk_value = clk_get_rate(clk) / ADC_CLK; +- clk_put(clk); +- +- if (clk_value < 7) { +- dev_err(&pdev->dev, "clock input less than min clock requirement\n"); +- goto err_disable_clk; +- } +- /* CLKDIV needs to be configured to the value minus 1 */ +- tscadc_writel(ts_dev, REG_CLKDIV, clk_value - 1); +- +- /* Enable wake-up of the SoC using touchscreen */ +- tscadc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); +- +- ctrl = CNTRLREG_STEPCONFIGWRT | +- CNTRLREG_TSCENB | +- CNTRLREG_STEPID; +- switch (ts_dev->wires) { +- case 4: +- ctrl |= CNTRLREG_4WIRE; +- break; +- case 5: +- ctrl |= CNTRLREG_5WIRE; +- break; +- case 8: +- ctrl |= CNTRLREG_8WIRE; +- break; +- } +- tscadc_writel(ts_dev, REG_CTRL, ctrl); +- +- tscadc_idle_config(ts_dev); +- tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); +- tscadc_step_config(ts_dev); +- tscadc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure); +- +- ctrl |= CNTRLREG_TSCSSENB; +- tscadc_writel(ts_dev, REG_CTRL, ctrl); +- +- input_dev->name = "ti-tsc-adc"; +- input_dev->dev.parent = &pdev->dev; +- +- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); +- input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); +- +- input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); +- input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); +- input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); +- +- /* register to the input system */ +- err = input_register_device(input_dev); +- if (err) +- goto err_disable_clk; +- +- platform_set_drvdata(pdev, ts_dev); +- return 0; +- +-err_disable_clk: +- clk_disable(ts_dev->tsc_ick); +- clk_put(ts_dev->tsc_ick); +-err_free_irq: +- free_irq(ts_dev->irq, ts_dev); +-err_unmap_regs: +- iounmap(ts_dev->tsc_base); +-err_release_mem_region: +- release_mem_region(res->start, resource_size(res)); +-err_free_mem: +- input_free_device(input_dev); +- kfree(ts_dev); +- return err; +-} +- +-static int __devexit tscadc_remove(struct platform_device *pdev) +-{ +- struct tscadc *ts_dev = platform_get_drvdata(pdev); +- struct resource *res; +- +- free_irq(ts_dev->irq, ts_dev); +- +- input_unregister_device(ts_dev->input); +- +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- iounmap(ts_dev->tsc_base); +- release_mem_region(res->start, resource_size(res)); +- +- clk_disable(ts_dev->tsc_ick); +- clk_put(ts_dev->tsc_ick); +- +- kfree(ts_dev); +- +- platform_set_drvdata(pdev, NULL); +- return 0; +-} +- +-static struct platform_driver ti_tsc_driver = { +- .probe = tscadc_probe, +- .remove = __devexit_p(tscadc_remove), +- .driver = { +- .name = "tsc", +- .owner = THIS_MODULE, +- }, +-}; +-module_platform_driver(ti_tsc_driver); +- +-MODULE_DESCRIPTION("TI touchscreen controller driver"); +-MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); +-MODULE_LICENSE("GPL"); +diff --git a/include/linux/input/ti_am335x_tsc.h b/include/linux/input/ti_am335x_tsc.h +new file mode 100644 +index 0000000..49269a2 +--- /dev/null ++++ b/include/linux/input/ti_am335x_tsc.h +@@ -0,0 +1,23 @@ ++#ifndef __LINUX_TI_AM335X_TSC_H ++#define __LINUX_TI_AM335X_TSC_H ++ ++/** ++ * struct tsc_data Touchscreen wire configuration ++ * @wires: Wires refer to application modes ++ * i.e. 4/5/8 wire touchscreen support ++ * on the platform. ++ * @x_plate_resistance: X plate resistance. ++ * @steps_to_configure: The sequencer supports a total of ++ * 16 programmable steps. ++ * A step configured to read a single ++ * co-ordinate value, can be applied ++ * more number of times for better results. ++ */ ++ ++struct tsc_data { ++ int wires; ++ int x_plate_resistance; ++ int steps_to_configure; ++}; ++ ++#endif +diff --git a/include/linux/input/ti_tscadc.h b/include/linux/input/ti_tscadc.h +deleted file mode 100644 +index ad442a3..0000000 +--- a/include/linux/input/ti_tscadc.h ++++ /dev/null +@@ -1,23 +0,0 @@ +-#ifndef __LINUX_TI_TSCADC_H +-#define __LINUX_TI_TSCADC_H +- +-/** +- * struct tsc_data Touchscreen wire configuration +- * @wires: Wires refer to application modes +- * i.e. 4/5/8 wire touchscreen support +- * on the platform. +- * @x_plate_resistance: X plate resistance. +- * @steps_to_configure: The sequencer supports a total of +- * 16 programmable steps. +- * A step configured to read a single +- * co-ordinate value, can be applied +- * more number of times for better results. +- */ +- +-struct tsc_data { +- int wires; +- int x_plate_resistance; +- int steps_to_configure; +-}; +- +-#endif diff --git a/patches/linux-3.7-rc6/0050-MFD-ti_tscadc-Add-support-for-TI-s-TSC-ADC-MFDevice.patch b/patches/linux-3.7-rc6/0050-MFD-ti_tscadc-Add-support-for-TI-s-TSC-ADC-MFDevice.patch new file mode 100644 index 0000000..7bade04 --- /dev/null +++ b/patches/linux-3.7-rc6/0050-MFD-ti_tscadc-Add-support-for-TI-s-TSC-ADC-MFDevice.patch @@ -0,0 +1,453 @@ +From f0239cfc7dffbfe1409dfb670899cb188ed257a1 Mon Sep 17 00:00:00 2001 +From: "Patil, Rachna" <rachna@ti.com> +Date: Tue, 16 Oct 2012 07:25:43 +0000 +Subject: [PATCH] MFD: ti_tscadc: Add support for TI's TSC/ADC MFDevice + +Add the mfd core driver which supports touchscreen +and ADC. +With this patch we are only adding infrastructure to +support the MFD clients. + +Signed-off-by: Patil, Rachna <rachna@ti.com> +--- + drivers/mfd/Kconfig | 11 ++ + drivers/mfd/Makefile | 1 + + drivers/mfd/ti_am335x_tscadc.c | 250 ++++++++++++++++++++++++++++++++++ + include/linux/mfd/ti_am335x_tscadc.h | 137 +++++++++++++++++++ + 4 files changed, 399 insertions(+) + create mode 100644 drivers/mfd/ti_am335x_tscadc.c + create mode 100644 include/linux/mfd/ti_am335x_tscadc.h + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index acab3ef..9bba7f7 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -94,6 +94,17 @@ config MFD_TI_SSP + To compile this driver as a module, choose M here: the + module will be called ti-ssp. + ++config MFD_TI_AM335X_TSCADC ++ tristate "TI ADC / Touch Screen chip support" ++ select MFD_CORE ++ select REGMAP ++ select REGMAP_MMIO ++ help ++ If you say yes here you get support for Texas Instruments series ++ of Touch Screen /ADC chips. ++ To compile this driver as a module, choose M here: the ++ module will be called ti_am335x_tscadc. ++ + config HTC_EGPIO + bool "HTC EGPIO support" + depends on GENERIC_HARDIRQS && GPIOLIB && ARM +diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile +index d8ccb63..442c17e 100644 +--- a/drivers/mfd/Makefile ++++ b/drivers/mfd/Makefile +@@ -16,6 +16,7 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o + obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o + obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o + obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o ++obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o + + obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o + obj-$(CONFIG_MFD_STMPE) += stmpe.o +diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c +new file mode 100644 +index 0000000..14df67b +--- /dev/null ++++ b/drivers/mfd/ti_am335x_tscadc.c +@@ -0,0 +1,250 @@ ++/* ++ * TI Touch Screen / ADC MFD driver ++ * ++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation version 2. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/clk.h> ++#include <linux/regmap.h> ++#include <linux/mfd/core.h> ++#include <linux/pm_runtime.h> ++ ++#include <linux/mfd/ti_am335x_tscadc.h> ++ ++static unsigned int tscadc_readl(struct ti_tscadc_dev *tsadc, unsigned int reg) ++{ ++ unsigned int val; ++ ++ regmap_read(tsadc->regmap_tscadc, reg, &val); ++ return val; ++} ++ ++static void tscadc_writel(struct ti_tscadc_dev *tsadc, unsigned int reg, ++ unsigned int val) ++{ ++ regmap_write(tsadc->regmap_tscadc, reg, val); ++} ++ ++static const struct regmap_config tscadc_regmap_config = { ++ .name = "ti_tscadc", ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++}; ++ ++static void tscadc_idle_config(struct ti_tscadc_dev *config) ++{ ++ unsigned int idleconfig; ++ ++ idleconfig = STEPCONFIG_YNN | STEPCONFIG_INM_ADCREFM | ++ STEPCONFIG_INP_ADCREFM | STEPCONFIG_YPN; ++ ++ tscadc_writel(config, REG_IDLECONFIG, idleconfig); ++} ++ ++static int __devinit ti_tscadc_probe(struct platform_device *pdev) ++{ ++ struct ti_tscadc_dev *tscadc; ++ struct resource *res; ++ struct clk *clk; ++ struct mfd_tscadc_board *pdata = pdev->dev.platform_data; ++ int irq; ++ int err, ctrl; ++ int clk_value, clock_rate; ++ ++ if (!pdata) { ++ dev_err(&pdev->dev, "Could not find platform data\n"); ++ return -EINVAL; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "no memory resource defined.\n"); ++ return -EINVAL; ++ } ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(&pdev->dev, "no irq ID is specified.\n"); ++ return -EINVAL; ++ } ++ ++ /* Allocate memory for device */ ++ tscadc = devm_kzalloc(&pdev->dev, ++ sizeof(struct ti_tscadc_dev), GFP_KERNEL); ++ if (!tscadc) { ++ dev_err(&pdev->dev, "failed to allocate memory.\n"); ++ return -ENOMEM; ++ } ++ tscadc->dev = &pdev->dev; ++ tscadc->irq = irq; ++ ++ res = devm_request_mem_region(&pdev->dev, ++ res->start, resource_size(res), pdev->name); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to reserve registers.\n"); ++ err = -EBUSY; ++ goto err; ++ } ++ ++ tscadc->tscadc_base = devm_ioremap(&pdev->dev, ++ res->start, resource_size(res)); ++ if (!tscadc->tscadc_base) { ++ dev_err(&pdev->dev, "failed to map registers.\n"); ++ err = -ENOMEM; ++ goto err; ++ } ++ ++ tscadc->regmap_tscadc = devm_regmap_init_mmio(&pdev->dev, ++ tscadc->tscadc_base, &tscadc_regmap_config); ++ if (IS_ERR(tscadc->regmap_tscadc)) { ++ dev_err(&pdev->dev, "regmap init failed\n"); ++ err = PTR_ERR(tscadc->regmap_tscadc); ++ goto err; ++ } ++ ++ pm_runtime_enable(&pdev->dev); ++ pm_runtime_get_sync(&pdev->dev); ++ ++ /* ++ * The TSC_ADC_Subsystem has 2 clock domains ++ * OCP_CLK and ADC_CLK. ++ * The ADC clock is expected to run at target of 3MHz, ++ * and expected to capture 12-bit data at a rate of 200 KSPS. ++ * The TSC_ADC_SS controller design assumes the OCP clock is ++ * at least 6x faster than the ADC clock. ++ */ ++ clk = clk_get(&pdev->dev, "adc_tsc_fck"); ++ if (IS_ERR(clk)) { ++ dev_err(&pdev->dev, "failed to get TSC fck\n"); ++ err = PTR_ERR(clk); ++ goto err_disable_clk; ++ } ++ clock_rate = clk_get_rate(clk); ++ clk_put(clk); ++ clk_value = clock_rate / ADC_CLK; ++ if (clk_value < MAX_CLK_DIV) { ++ dev_err(&pdev->dev, "clock input less than min clock requirement\n"); ++ err = -EINVAL; ++ goto err_disable_clk; ++ } ++ /* TSCADC_CLKDIV needs to be configured to the value minus 1 */ ++ clk_value = clk_value - 1; ++ tscadc_writel(tscadc, REG_CLKDIV, clk_value); ++ ++ /* Set the control register bits */ ++ ctrl = CNTRLREG_STEPCONFIGWRT | ++ CNTRLREG_TSCENB | ++ CNTRLREG_STEPID | ++ CNTRLREG_4WIRE; ++ tscadc_writel(tscadc, REG_CTRL, ctrl); ++ ++ /* Set register bits for Idle Config Mode */ ++ tscadc_idle_config(tscadc); ++ ++ /* Enable the TSC module enable bit */ ++ ctrl = tscadc_readl(tscadc, REG_CTRL); ++ ctrl |= CNTRLREG_TSCSSENB; ++ tscadc_writel(tscadc, REG_CTRL, ctrl); ++ ++ err = mfd_add_devices(&pdev->dev, pdev->id, tscadc->cells, ++ TSCADC_CELLS, NULL, 0, NULL); ++ if (err < 0) ++ goto err_disable_clk; ++ ++ device_init_wakeup(&pdev->dev, true); ++ platform_set_drvdata(pdev, tscadc); ++ ++ return 0; ++ ++err_disable_clk: ++ pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++err: ++ return err; ++} ++ ++static int __devexit ti_tscadc_remove(struct platform_device *pdev) ++{ ++ struct ti_tscadc_dev *tscadc = platform_get_drvdata(pdev); ++ ++ tscadc_writel(tscadc, REG_SE, 0x00); ++ ++ pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ ++ mfd_remove_devices(tscadc->dev); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int tscadc_suspend(struct device *dev) ++{ ++ struct ti_tscadc_dev *tscadc_dev = dev_get_drvdata(dev); ++ ++ tscadc_writel(tscadc_dev, REG_SE, 0x00); ++ pm_runtime_put_sync(dev); ++ ++ return 0; ++} ++ ++static int tscadc_resume(struct device *dev) ++{ ++ struct ti_tscadc_dev *tscadc_dev = dev_get_drvdata(dev); ++ unsigned int restore, ctrl; ++ ++ pm_runtime_get_sync(dev); ++ ++ /* context restore */ ++ ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_TSCENB | ++ CNTRLREG_STEPID | CNTRLREG_4WIRE; ++ tscadc_writel(tscadc_dev, REG_CTRL, ctrl); ++ tscadc_idle_config(tscadc_dev); ++ tscadc_writel(tscadc_dev, REG_SE, STPENB_STEPENB); ++ restore = tscadc_readl(tscadc_dev, REG_CTRL); ++ tscadc_writel(tscadc_dev, REG_CTRL, ++ (restore | CNTRLREG_TSCSSENB)); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops tscadc_pm_ops = { ++ .suspend = tscadc_suspend, ++ .resume = tscadc_resume, ++}; ++#define TSCADC_PM_OPS (&tscadc_pm_ops) ++#else ++#define TSCADC_PM_OPS NULL ++#endif ++ ++static struct platform_driver ti_tscadc_driver = { ++ .driver = { ++ .name = "ti_tscadc", ++ .owner = THIS_MODULE, ++ .pm = TSCADC_PM_OPS, ++ }, ++ .probe = ti_tscadc_probe, ++ .remove = __devexit_p(ti_tscadc_remove), ++ ++}; ++ ++module_platform_driver(ti_tscadc_driver); ++ ++MODULE_DESCRIPTION("TI touchscreen / ADC MFD controller driver"); ++MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); ++MODULE_LICENSE("GPL"); +diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h +new file mode 100644 +index 0000000..b7232b1 +--- /dev/null ++++ b/include/linux/mfd/ti_am335x_tscadc.h +@@ -0,0 +1,137 @@ ++#ifndef __LINUX_TI_AM335X_TSCADC_MFD_H ++#define __LINUX_TI_AM335X_TSCADC_MFD_H ++ ++/* ++ * TI Touch Screen / ADC MFD driver ++ * ++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation version 2. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/mfd/core.h> ++ ++#define REG_RAWIRQSTATUS 0x024 ++#define REG_IRQSTATUS 0x028 ++#define REG_IRQENABLE 0x02C ++#define REG_IRQCLR 0x030 ++#define REG_IRQWAKEUP 0x034 ++#define REG_CTRL 0x040 ++#define REG_ADCFSM 0x044 ++#define REG_CLKDIV 0x04C ++#define REG_SE 0x054 ++#define REG_IDLECONFIG 0x058 ++#define REG_CHARGECONFIG 0x05C ++#define REG_CHARGEDELAY 0x060 ++#define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8)) ++#define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8)) ++#define REG_FIFO0CNT 0xE4 ++#define REG_FIFO0THR 0xE8 ++#define REG_FIFO1CNT 0xF0 ++#define REG_FIFO1THR 0xF4 ++#define REG_FIFO0 0x100 ++#define REG_FIFO1 0x200 ++ ++/* Register Bitfields */ ++/* IRQ wakeup enable */ ++#define IRQWKUP_ENB BIT(0) ++ ++/* Step Enable */ ++#define STEPENB_MASK (0x1FFFF << 0) ++#define STEPENB(val) ((val) << 0) ++#define STPENB_STEPENB STEPENB(0x1FFFF) ++ ++/* IRQ enable */ ++#define IRQENB_HW_PEN BIT(0) ++#define IRQENB_FIFO0THRES BIT(2) ++#define IRQENB_FIFO1THRES BIT(5) ++#define IRQENB_PENUP BIT(9) ++ ++/* Step Configuration */ ++#define STEPCONFIG_MODE_MASK (3 << 0) ++#define STEPCONFIG_MODE(val) ((val) << 0) ++#define STEPCONFIG_MODE_HWSYNC STEPCONFIG_MODE(2) ++#define STEPCONFIG_AVG_MASK (7 << 2) ++#define STEPCONFIG_AVG(val) ((val) << 2) ++#define STEPCONFIG_AVG_16 STEPCONFIG_AVG(4) ++#define STEPCONFIG_XPP BIT(5) ++#define STEPCONFIG_XNN BIT(6) ++#define STEPCONFIG_YPP BIT(7) ++#define STEPCONFIG_YNN BIT(8) ++#define STEPCONFIG_XNP BIT(9) ++#define STEPCONFIG_YPN BIT(10) ++#define STEPCONFIG_INM_MASK (0xF << 15) ++#define STEPCONFIG_INM(val) ((val) << 15) ++#define STEPCONFIG_INM_ADCREFM STEPCONFIG_INM(8) ++#define STEPCONFIG_INP_MASK (0xF << 19) ++#define STEPCONFIG_INP(val) ((val) << 19) ++#define STEPCONFIG_INP_AN2 STEPCONFIG_INP(2) ++#define STEPCONFIG_INP_AN3 STEPCONFIG_INP(3) ++#define STEPCONFIG_INP_AN4 STEPCONFIG_INP(4) ++#define STEPCONFIG_INP_ADCREFM STEPCONFIG_INP(8) ++#define STEPCONFIG_FIFO1 BIT(26) ++ ++/* Delay register */ ++#define STEPDELAY_OPEN_MASK (0x3FFFF << 0) ++#define STEPDELAY_OPEN(val) ((val) << 0) ++#define STEPCONFIG_OPENDLY STEPDELAY_OPEN(0x098) ++#define STEPDELAY_SAMPLE_MASK (0xFF << 24) ++#define STEPDELAY_SAMPLE(val) ((val) << 24) ++#define STEPCONFIG_SAMPLEDLY STEPDELAY_SAMPLE(0) ++ ++/* Charge Config */ ++#define STEPCHARGE_RFP_MASK (7 << 12) ++#define STEPCHARGE_RFP(val) ((val) << 12) ++#define STEPCHARGE_RFP_XPUL STEPCHARGE_RFP(1) ++#define STEPCHARGE_INM_MASK (0xF << 15) ++#define STEPCHARGE_INM(val) ((val) << 15) ++#define STEPCHARGE_INM_AN1 STEPCHARGE_INM(1) ++#define STEPCHARGE_INP_MASK (0xF << 19) ++#define STEPCHARGE_INP(val) ((val) << 19) ++#define STEPCHARGE_INP_AN1 STEPCHARGE_INP(1) ++#define STEPCHARGE_RFM_MASK (3 << 23) ++#define STEPCHARGE_RFM(val) ((val) << 23) ++#define STEPCHARGE_RFM_XNUR STEPCHARGE_RFM(1) ++ ++/* Charge delay */ ++#define CHARGEDLY_OPEN_MASK (0x3FFFF << 0) ++#define CHARGEDLY_OPEN(val) ((val) << 0) ++#define CHARGEDLY_OPENDLY CHARGEDLY_OPEN(1) ++ ++/* Control register */ ++#define CNTRLREG_TSCSSENB BIT(0) ++#define CNTRLREG_STEPID BIT(1) ++#define CNTRLREG_STEPCONFIGWRT BIT(2) ++#define CNTRLREG_POWERDOWN BIT(4) ++#define CNTRLREG_AFE_CTRL_MASK (3 << 5) ++#define CNTRLREG_AFE_CTRL(val) ((val) << 5) ++#define CNTRLREG_4WIRE CNTRLREG_AFE_CTRL(1) ++#define CNTRLREG_5WIRE CNTRLREG_AFE_CTRL(2) ++#define CNTRLREG_8WIRE CNTRLREG_AFE_CTRL(3) ++#define CNTRLREG_TSCENB BIT(7) ++ ++#define ADC_CLK 3000000 ++#define MAX_CLK_DIV 7 ++ ++#define TSCADC_CELLS 0 ++ ++struct mfd_tscadc_board { ++ struct tsc_data *tsc_init; ++}; ++ ++struct ti_tscadc_dev { ++ struct device *dev; ++ struct regmap *regmap_tscadc; ++ void __iomem *tscadc_base; ++ int irq; ++ struct mfd_cell cells[TSCADC_CELLS]; ++}; ++ ++#endif diff --git a/patches/linux-3.7-rc6/0051-input-TSC-ti_tsc-Convert-TSC-into-a-MFDevice.patch b/patches/linux-3.7-rc6/0051-input-TSC-ti_tsc-Convert-TSC-into-a-MFDevice.patch new file mode 100644 index 0000000..11bdb5f --- /dev/null +++ b/patches/linux-3.7-rc6/0051-input-TSC-ti_tsc-Convert-TSC-into-a-MFDevice.patch @@ -0,0 +1,571 @@ +From 0191d4a7838cc6c437d8811ec630e26f10abe116 Mon Sep 17 00:00:00 2001 +From: "Patil, Rachna" <rachna@ti.com> +Date: Tue, 16 Oct 2012 07:25:44 +0000 +Subject: [PATCH] input: TSC: ti_tsc: Convert TSC into a MFDevice + +This patch converts touchscreen into a MFD client. +All the register definitions, clock initialization, +etc has been moved to MFD core driver. + +Signed-off-by: Patil, Rachna <rachna@ti.com> +--- + drivers/input/touchscreen/Kconfig | 2 +- + drivers/input/touchscreen/ti_am335x_tsc.c | 318 +++++++++-------------------- + drivers/mfd/ti_am335x_tscadc.c | 11 + + include/linux/mfd/ti_am335x_tscadc.h | 10 +- + 4 files changed, 118 insertions(+), 223 deletions(-) + +diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig +index d31dc5f..0c45cad 100644 +--- a/drivers/input/touchscreen/Kconfig ++++ b/drivers/input/touchscreen/Kconfig +@@ -531,7 +531,7 @@ config TOUCHSCREEN_TOUCHWIN + + config TOUCHSCREEN_TI_AM335X_TSC + tristate "TI Touchscreen Interface" +- depends on ARCH_OMAP2PLUS ++ depends on MFD_TI_AM335X_TSCADC + help + Say Y here if you have 4/5/8 wire touchscreen controller + to be connected to the ADC controller on your TI AM335x SoC. +diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c +index 462950a..7a18a8a 100644 +--- a/drivers/input/touchscreen/ti_am335x_tsc.c ++++ b/drivers/input/touchscreen/ti_am335x_tsc.c +@@ -27,106 +27,15 @@ + #include <linux/input/ti_am335x_tsc.h> + #include <linux/delay.h> + +-#define REG_RAWIRQSTATUS 0x024 +-#define REG_IRQSTATUS 0x028 +-#define REG_IRQENABLE 0x02C +-#define REG_IRQWAKEUP 0x034 +-#define REG_CTRL 0x040 +-#define REG_ADCFSM 0x044 +-#define REG_CLKDIV 0x04C +-#define REG_SE 0x054 +-#define REG_IDLECONFIG 0x058 +-#define REG_CHARGECONFIG 0x05C +-#define REG_CHARGEDELAY 0x060 +-#define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8)) +-#define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8)) +-#define REG_FIFO0CNT 0xE4 +-#define REG_FIFO0THR 0xE8 +-#define REG_FIFO1THR 0xF4 +-#define REG_FIFO0 0x100 +-#define REG_FIFO1 0x200 +- +-/* Register Bitfields */ +-#define IRQWKUP_ENB BIT(0) +- +-/* Step Enable */ +-#define STEPENB_MASK (0x1FFFF << 0) +-#define STEPENB(val) (val << 0) +-#define STPENB_STEPENB STEPENB(0x7FFF) +- +-/* IRQ enable */ +-#define IRQENB_FIFO0THRES BIT(2) +-#define IRQENB_FIFO1THRES BIT(5) +-#define IRQENB_PENUP BIT(9) +- +-/* Step Configuration */ +-#define STEPCONFIG_MODE_MASK (3 << 0) +-#define STEPCONFIG_MODE(val) (val << 0) +-#define STEPCONFIG_MODE_HWSYNC STEPCONFIG_MODE(2) +-#define STEPCONFIG_AVG_MASK (7 << 2) +-#define STEPCONFIG_AVG(val) (val << 2) +-#define STEPCONFIG_AVG_16 STEPCONFIG_AVG(4) +-#define STEPCONFIG_XPP BIT(5) +-#define STEPCONFIG_XNN BIT(6) +-#define STEPCONFIG_YPP BIT(7) +-#define STEPCONFIG_YNN BIT(8) +-#define STEPCONFIG_XNP BIT(9) +-#define STEPCONFIG_YPN BIT(10) +-#define STEPCONFIG_INM_MASK (0xF << 15) +-#define STEPCONFIG_INM(val) (val << 15) +-#define STEPCONFIG_INM_ADCREFM STEPCONFIG_INM(8) +-#define STEPCONFIG_INP_MASK (0xF << 19) +-#define STEPCONFIG_INP(val) (val << 19) +-#define STEPCONFIG_INP_AN2 STEPCONFIG_INP(2) +-#define STEPCONFIG_INP_AN3 STEPCONFIG_INP(3) +-#define STEPCONFIG_INP_AN4 STEPCONFIG_INP(4) +-#define STEPCONFIG_INP_ADCREFM STEPCONFIG_INP(8) +-#define STEPCONFIG_FIFO1 BIT(26) +- +-/* Delay register */ +-#define STEPDELAY_OPEN_MASK (0x3FFFF << 0) +-#define STEPDELAY_OPEN(val) (val << 0) +-#define STEPCONFIG_OPENDLY STEPDELAY_OPEN(0x098) +- +-/* Charge Config */ +-#define STEPCHARGE_RFP_MASK (7 << 12) +-#define STEPCHARGE_RFP(val) (val << 12) +-#define STEPCHARGE_RFP_XPUL STEPCHARGE_RFP(1) +-#define STEPCHARGE_INM_MASK (0xF << 15) +-#define STEPCHARGE_INM(val) (val << 15) +-#define STEPCHARGE_INM_AN1 STEPCHARGE_INM(1) +-#define STEPCHARGE_INP_MASK (0xF << 19) +-#define STEPCHARGE_INP(val) (val << 19) +-#define STEPCHARGE_INP_AN1 STEPCHARGE_INP(1) +-#define STEPCHARGE_RFM_MASK (3 << 23) +-#define STEPCHARGE_RFM(val) (val << 23) +-#define STEPCHARGE_RFM_XNUR STEPCHARGE_RFM(1) +- +-/* Charge delay */ +-#define CHARGEDLY_OPEN_MASK (0x3FFFF << 0) +-#define CHARGEDLY_OPEN(val) (val << 0) +-#define CHARGEDLY_OPENDLY CHARGEDLY_OPEN(1) +- +-/* Control register */ +-#define CNTRLREG_TSCSSENB BIT(0) +-#define CNTRLREG_STEPID BIT(1) +-#define CNTRLREG_STEPCONFIGWRT BIT(2) +-#define CNTRLREG_AFE_CTRL_MASK (3 << 5) +-#define CNTRLREG_AFE_CTRL(val) (val << 5) +-#define CNTRLREG_4WIRE CNTRLREG_AFE_CTRL(1) +-#define CNTRLREG_5WIRE CNTRLREG_AFE_CTRL(2) +-#define CNTRLREG_8WIRE CNTRLREG_AFE_CTRL(3) +-#define CNTRLREG_TSCENB BIT(7) ++#include <linux/mfd/ti_am335x_tscadc.h> + + #define ADCFSM_STEPID 0x10 + #define SEQ_SETTLE 275 +-#define ADC_CLK 3000000 + #define MAX_12BIT ((1 << 12) - 1) + + struct titsc { + struct input_dev *input; +- struct clk *tsc_ick; +- void __iomem *tsc_base; ++ struct ti_tscadc_dev *mfd_tscadc; + unsigned int irq; + unsigned int wires; + unsigned int x_plate_resistance; +@@ -136,13 +45,13 @@ struct titsc { + + static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) + { +- return readl(ts->tsc_base + reg); ++ return readl(ts->mfd_tscadc->tscadc_base + reg); + } + + static void titsc_writel(struct titsc *tsc, unsigned int reg, + unsigned int val) + { +- writel(val, tsc->tsc_base + reg); ++ writel(val, tsc->mfd_tscadc->tscadc_base + reg); + } + + static void titsc_step_config(struct titsc *ts_dev) +@@ -219,17 +128,7 @@ static void titsc_step_config(struct titsc *ts_dev) + titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2), + STEPCONFIG_OPENDLY); + +- titsc_writel(ts_dev, REG_SE, STPENB_STEPENB); +-} +- +-static void titsc_idle_config(struct titsc *ts_config) +-{ +- unsigned int idleconfig; +- +- idleconfig = STEPCONFIG_YNN | +- STEPCONFIG_INM_ADCREFM | +- STEPCONFIG_YPN | STEPCONFIG_INP_ADCREFM; +- titsc_writel(ts_config, REG_IDLECONFIG, idleconfig); ++ titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC); + } + + static void titsc_read_coordinates(struct titsc *ts_dev, +@@ -239,7 +138,7 @@ static void titsc_read_coordinates(struct titsc *ts_dev, + unsigned int prev_val_x = ~0, prev_val_y = ~0; + unsigned int prev_diff_x = ~0, prev_diff_y = ~0; + unsigned int read, diff; +- unsigned int i; ++ unsigned int i, channel; + + /* + * Delta filter is used to remove large variations in sampled +@@ -250,21 +149,32 @@ static void titsc_read_coordinates(struct titsc *ts_dev, + * if true the value is reported to the sub system. + */ + for (i = 0; i < fifocount - 1; i++) { +- read = titsc_readl(ts_dev, REG_FIFO0) & 0xfff; +- diff = abs(read - prev_val_x); +- if (diff < prev_diff_x) { +- prev_diff_x = diff; +- *x = read; ++ read = titsc_readl(ts_dev, REG_FIFO0); ++ channel = read & 0xf0000; ++ channel = channel >> 0x10; ++ if ((channel >= 0) && (channel < ts_dev->steps_to_configure)) { ++ read &= 0xfff; ++ diff = abs(read - prev_val_x); ++ if (diff < prev_diff_x) { ++ prev_diff_x = diff; ++ *x = read; ++ } ++ prev_val_x = read; + } +- prev_val_x = read; + +- read = titsc_readl(ts_dev, REG_FIFO1) & 0xfff; +- diff = abs(read - prev_val_y); +- if (diff < prev_diff_y) { +- prev_diff_y = diff; +- *y = read; ++ read = titsc_readl(ts_dev, REG_FIFO1); ++ channel = read & 0xf0000; ++ channel = channel >> 0x10; ++ if ((channel >= ts_dev->steps_to_configure) && ++ (channel < (2 * ts_dev->steps_to_configure - 1))) { ++ read &= 0xfff; ++ diff = abs(read - prev_val_y); ++ if (diff < prev_diff_y) { ++ prev_diff_y = diff; ++ *y = read; ++ } ++ prev_val_y = read; + } +- prev_val_y = read; + } + } + +@@ -276,6 +186,8 @@ static irqreturn_t titsc_irq(int irq, void *dev) + unsigned int x = 0, y = 0; + unsigned int z1, z2, z; + unsigned int fsm; ++ unsigned int fifo1count, fifo0count; ++ int i; + + status = titsc_readl(ts_dev, REG_IRQSTATUS); + if (status & IRQENB_FIFO0THRES) { +@@ -284,6 +196,14 @@ static irqreturn_t titsc_irq(int irq, void *dev) + z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff; + z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff; + ++ fifo1count = titsc_readl(ts_dev, REG_FIFO1CNT); ++ for (i = 0; i < fifo1count; i++) ++ titsc_readl(ts_dev, REG_FIFO1); ++ ++ fifo0count = titsc_readl(ts_dev, REG_FIFO0CNT); ++ for (i = 0; i < fifo0count; i++) ++ titsc_readl(ts_dev, REG_FIFO0); ++ + if (ts_dev->pen_down && z1 != 0 && z2 != 0) { + /* + * Calculate pressure using formula +@@ -330,7 +250,7 @@ static irqreturn_t titsc_irq(int irq, void *dev) + + titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); + +- titsc_writel(ts_dev, REG_SE, STPENB_STEPENB); ++ titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC); + return IRQ_HANDLED; + } + +@@ -340,28 +260,16 @@ static irqreturn_t titsc_irq(int irq, void *dev) + + static int __devinit titsc_probe(struct platform_device *pdev) + { +- const struct tsc_data *pdata = pdev->dev.platform_data; +- struct resource *res; + struct titsc *ts_dev; + struct input_dev *input_dev; +- struct clk *clk; ++ struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; ++ struct mfd_tscadc_board *pdata; + int err; +- int clk_value, ctrl, irq; + +- if (!pdata) { +- dev_err(&pdev->dev, "missing platform data.\n"); +- return -EINVAL; +- } +- +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!res) { +- dev_err(&pdev->dev, "no memory resource defined.\n"); +- return -EINVAL; +- } ++ pdata = tscadc_dev->dev->platform_data; + +- irq = platform_get_irq(pdev, 0); +- if (irq < 0) { +- dev_err(&pdev->dev, "no irq ID is specified.\n"); ++ if (!pdata) { ++ dev_err(&pdev->dev, "Could not find platform data\n"); + return -EINVAL; + } + +@@ -374,85 +282,26 @@ static int __devinit titsc_probe(struct platform_device *pdev) + goto err_free_mem; + } + ++ tscadc_dev->tsc = ts_dev; ++ ts_dev->mfd_tscadc = tscadc_dev; + ts_dev->input = input_dev; +- ts_dev->irq = irq; +- ts_dev->wires = pdata->wires; +- ts_dev->x_plate_resistance = pdata->x_plate_resistance; +- ts_dev->steps_to_configure = pdata->steps_to_configure; +- +- res = request_mem_region(res->start, resource_size(res), pdev->name); +- if (!res) { +- dev_err(&pdev->dev, "failed to reserve registers.\n"); +- err = -EBUSY; +- goto err_free_mem; +- } +- +- ts_dev->tsc_base = ioremap(res->start, resource_size(res)); +- if (!ts_dev->tsc_base) { +- dev_err(&pdev->dev, "failed to map registers.\n"); +- err = -ENOMEM; +- goto err_release_mem_region; +- } ++ ts_dev->irq = tscadc_dev->irq; ++ ts_dev->wires = pdata->tsc_init->wires; ++ ts_dev->x_plate_resistance = pdata->tsc_init->x_plate_resistance; ++ ts_dev->steps_to_configure = pdata->tsc_init->steps_to_configure; + + err = request_irq(ts_dev->irq, titsc_irq, + 0, pdev->dev.driver->name, ts_dev); + if (err) { + dev_err(&pdev->dev, "failed to allocate irq.\n"); +- goto err_unmap_regs; +- } +- +- ts_dev->tsc_ick = clk_get(&pdev->dev, "adc_tsc_ick"); +- if (IS_ERR(ts_dev->tsc_ick)) { +- dev_err(&pdev->dev, "failed to get TSC ick\n"); +- goto err_free_irq; +- } +- clk_enable(ts_dev->tsc_ick); +- +- clk = clk_get(&pdev->dev, "adc_tsc_fck"); +- if (IS_ERR(clk)) { +- dev_err(&pdev->dev, "failed to get TSC fck\n"); +- err = PTR_ERR(clk); +- goto err_disable_clk; +- } +- +- clk_value = clk_get_rate(clk) / ADC_CLK; +- clk_put(clk); +- +- if (clk_value < 7) { +- dev_err(&pdev->dev, "clock input less than min clock requirement\n"); +- goto err_disable_clk; +- } +- /* CLKDIV needs to be configured to the value minus 1 */ +- titsc_writel(ts_dev, REG_CLKDIV, clk_value - 1); +- +- /* Enable wake-up of the SoC using touchscreen */ +- titsc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); +- +- ctrl = CNTRLREG_STEPCONFIGWRT | +- CNTRLREG_TSCENB | +- CNTRLREG_STEPID; +- switch (ts_dev->wires) { +- case 4: +- ctrl |= CNTRLREG_4WIRE; +- break; +- case 5: +- ctrl |= CNTRLREG_5WIRE; +- break; +- case 8: +- ctrl |= CNTRLREG_8WIRE; +- break; ++ goto err_free_mem; + } +- titsc_writel(ts_dev, REG_CTRL, ctrl); + +- titsc_idle_config(ts_dev); + titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); + titsc_step_config(ts_dev); + titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure); + +- ctrl |= CNTRLREG_TSCSSENB; +- titsc_writel(ts_dev, REG_CTRL, ctrl); +- +- input_dev->name = "ti-tsc-adc"; ++ input_dev->name = "ti-tsc"; + input_dev->dev.parent = &pdev->dev; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); +@@ -465,20 +314,13 @@ static int __devinit titsc_probe(struct platform_device *pdev) + /* register to the input system */ + err = input_register_device(input_dev); + if (err) +- goto err_disable_clk; ++ goto err_free_irq; + + platform_set_drvdata(pdev, ts_dev); + return 0; + +-err_disable_clk: +- clk_disable(ts_dev->tsc_ick); +- clk_put(ts_dev->tsc_ick); + err_free_irq: + free_irq(ts_dev->irq, ts_dev); +-err_unmap_regs: +- iounmap(ts_dev->tsc_base); +-err_release_mem_region: +- release_mem_region(res->start, resource_size(res)); + err_free_mem: + input_free_device(input_dev); + kfree(ts_dev); +@@ -487,32 +329,66 @@ err_free_mem: + + static int __devexit titsc_remove(struct platform_device *pdev) + { +- struct titsc *ts_dev = platform_get_drvdata(pdev); +- struct resource *res; ++ struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; ++ struct titsc *ts_dev = tscadc_dev->tsc; + + free_irq(ts_dev->irq, ts_dev); + + input_unregister_device(ts_dev->input); + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- iounmap(ts_dev->tsc_base); +- release_mem_region(res->start, resource_size(res)); ++ platform_set_drvdata(pdev, NULL); ++ kfree(ts_dev); ++ return 0; ++} + +- clk_disable(ts_dev->tsc_ick); +- clk_put(ts_dev->tsc_ick); ++#ifdef CONFIG_PM ++static int titsc_suspend(struct device *dev) ++{ ++ struct ti_tscadc_dev *tscadc_dev = dev->platform_data; ++ struct titsc *ts_dev = tscadc_dev->tsc; ++ unsigned int idle; ++ ++ if (device_may_wakeup(tscadc_dev->dev)) { ++ idle = titsc_readl(ts_dev, REG_IRQENABLE); ++ titsc_writel(ts_dev, REG_IRQENABLE, ++ (idle | IRQENB_HW_PEN)); ++ titsc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); ++ } ++ return 0; ++} + +- kfree(ts_dev); ++static int titsc_resume(struct device *dev) ++{ ++ struct ti_tscadc_dev *tscadc_dev = dev->platform_data; ++ struct titsc *ts_dev = tscadc_dev->tsc; + +- platform_set_drvdata(pdev, NULL); ++ if (device_may_wakeup(tscadc_dev->dev)) { ++ titsc_writel(ts_dev, REG_IRQWAKEUP, ++ 0x00); ++ titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); ++ } ++ titsc_step_config(ts_dev); ++ titsc_writel(ts_dev, REG_FIFO0THR, ++ ts_dev->steps_to_configure); + return 0; + } + ++static const struct dev_pm_ops titsc_pm_ops = { ++ .suspend = titsc_suspend, ++ .resume = titsc_resume, ++}; ++#define TITSC_PM_OPS (&titsc_pm_ops) ++#else ++#define TITSC_PM_OPS NULL ++#endif ++ + static struct platform_driver ti_tsc_driver = { + .probe = titsc_probe, + .remove = __devexit_p(titsc_remove), + .driver = { + .name = "tsc", + .owner = THIS_MODULE, ++ .pm = TITSC_PM_OPS, + }, + }; + module_platform_driver(ti_tsc_driver); +diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c +index 14df67b..d812be4 100644 +--- a/drivers/mfd/ti_am335x_tscadc.c ++++ b/drivers/mfd/ti_am335x_tscadc.c +@@ -24,6 +24,7 @@ + #include <linux/pm_runtime.h> + + #include <linux/mfd/ti_am335x_tscadc.h> ++#include <linux/input/ti_am335x_tsc.h> + + static unsigned int tscadc_readl(struct ti_tscadc_dev *tsadc, unsigned int reg) + { +@@ -62,15 +63,19 @@ static int __devinit ti_tscadc_probe(struct platform_device *pdev) + struct resource *res; + struct clk *clk; + struct mfd_tscadc_board *pdata = pdev->dev.platform_data; ++ struct mfd_cell *cell; + int irq; + int err, ctrl; + int clk_value, clock_rate; ++ int tsc_wires; + + if (!pdata) { + dev_err(&pdev->dev, "Could not find platform data\n"); + return -EINVAL; + } + ++ tsc_wires = pdata->tsc_init->wires; ++ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no memory resource defined.\n"); +@@ -161,6 +166,12 @@ static int __devinit ti_tscadc_probe(struct platform_device *pdev) + ctrl |= CNTRLREG_TSCSSENB; + tscadc_writel(tscadc, REG_CTRL, ctrl); + ++ /* TSC Cell */ ++ cell = &tscadc->cells[TSC_CELL]; ++ cell->name = "tsc"; ++ cell->platform_data = tscadc; ++ cell->pdata_size = sizeof(*tscadc); ++ + err = mfd_add_devices(&pdev->dev, pdev->id, tscadc->cells, + TSCADC_CELLS, NULL, 0, NULL); + if (err < 0) +diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h +index b7232b1..fc18b2e 100644 +--- a/include/linux/mfd/ti_am335x_tscadc.h ++++ b/include/linux/mfd/ti_am335x_tscadc.h +@@ -47,6 +47,7 @@ + #define STEPENB_MASK (0x1FFFF << 0) + #define STEPENB(val) ((val) << 0) + #define STPENB_STEPENB STEPENB(0x1FFFF) ++#define STPENB_STEPENB_TC STEPENB(0x1FFF) + + /* IRQ enable */ + #define IRQENB_HW_PEN BIT(0) +@@ -120,7 +121,11 @@ + #define ADC_CLK 3000000 + #define MAX_CLK_DIV 7 + +-#define TSCADC_CELLS 0 ++#define TSCADC_CELLS 1 ++ ++enum tscadc_cells { ++ TSC_CELL, ++}; + + struct mfd_tscadc_board { + struct tsc_data *tsc_init; +@@ -132,6 +137,9 @@ struct ti_tscadc_dev { + void __iomem *tscadc_base; + int irq; + struct mfd_cell cells[TSCADC_CELLS]; ++ ++ /* tsc device */ ++ struct titsc *tsc; + }; + + #endif diff --git a/patches/linux-3.7-rc6/0052-IIO-ADC-tiadc-Add-support-of-TI-s-ADC-driver.patch b/patches/linux-3.7-rc6/0052-IIO-ADC-tiadc-Add-support-of-TI-s-ADC-driver.patch new file mode 100644 index 0000000..55e3b66 --- /dev/null +++ b/patches/linux-3.7-rc6/0052-IIO-ADC-tiadc-Add-support-of-TI-s-ADC-driver.patch @@ -0,0 +1,420 @@ +From 1c87d22d7a5671164abd42a6478cf536a3637fee Mon Sep 17 00:00:00 2001 +From: "Patil, Rachna" <rachna@ti.com> +Date: Tue, 16 Oct 2012 07:25:45 +0000 +Subject: [PATCH] IIO : ADC: tiadc: Add support of TI's ADC driver + +This patch adds support for TI's ADC driver. +This is a multifunctional device. +Analog input lines are provided on which +voltage measurements can be carried out. +You can have upto 8 input lines. + +Signed-off-by: Patil, Rachna <rachna@ti.com> +Acked-by: Jonathan Cameron <jic23@kernel.org> +--- + drivers/iio/adc/Kconfig | 7 + + drivers/iio/adc/Makefile | 1 + + drivers/iio/adc/ti_am335x_adc.c | 260 +++++++++++++++++++++++++++ + drivers/mfd/ti_am335x_tscadc.c | 18 +- + include/linux/mfd/ti_am335x_tscadc.h | 9 +- + include/linux/platform_data/ti_am335x_adc.h | 14 ++ + 6 files changed, 307 insertions(+), 2 deletions(-) + create mode 100644 drivers/iio/adc/ti_am335x_adc.c + create mode 100644 include/linux/platform_data/ti_am335x_adc.h + +diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig +index 4927581..1401ed1 100644 +--- a/drivers/iio/adc/Kconfig ++++ b/drivers/iio/adc/Kconfig +@@ -60,4 +60,11 @@ config LP8788_ADC + help + Say yes here to build support for TI LP8788 ADC. + ++config TI_AM335X_ADC ++ tristate "TI's ADC driver" ++ depends on MFD_TI_AM335X_TSCADC ++ help ++ Say yes here to build support for Texas Instruments ADC ++ driver which is also a MFD client. ++ + endmenu +diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile +index 900995d..4410a90 100644 +--- a/drivers/iio/adc/Makefile ++++ b/drivers/iio/adc/Makefile +@@ -8,3 +8,4 @@ obj-$(CONFIG_AD7476) += ad7476.o + obj-$(CONFIG_AD7791) += ad7791.o + obj-$(CONFIG_AT91_ADC) += at91_adc.o + obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o ++obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o +diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c +new file mode 100644 +index 0000000..02a43c8 +--- /dev/null ++++ b/drivers/iio/adc/ti_am335x_adc.c +@@ -0,0 +1,260 @@ ++/* ++ * TI ADC MFD driver ++ * ++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation version 2. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/err.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/iio/iio.h> ++ ++#include <linux/mfd/ti_am335x_tscadc.h> ++#include <linux/platform_data/ti_am335x_adc.h> ++ ++struct tiadc_device { ++ struct ti_tscadc_dev *mfd_tscadc; ++ int channels; ++}; ++ ++static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg) ++{ ++ return readl(adc->mfd_tscadc->tscadc_base + reg); ++} ++ ++static void tiadc_writel(struct tiadc_device *adc, unsigned int reg, ++ unsigned int val) ++{ ++ writel(val, adc->mfd_tscadc->tscadc_base + reg); ++} ++ ++static void tiadc_step_config(struct tiadc_device *adc_dev) ++{ ++ unsigned int stepconfig; ++ int i, channels = 0, steps; ++ ++ /* ++ * There are 16 configurable steps and 8 analog input ++ * lines available which are shared between Touchscreen and ADC. ++ * ++ * Steps backwards i.e. from 16 towards 0 are used by ADC ++ * depending on number of input lines needed. ++ * Channel would represent which analog input ++ * needs to be given to ADC to digitalize data. ++ */ ++ ++ steps = TOTAL_STEPS - adc_dev->channels; ++ channels = TOTAL_CHANNELS - adc_dev->channels; ++ ++ stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1; ++ ++ for (i = (steps + 1); i <= TOTAL_STEPS; i++) { ++ tiadc_writel(adc_dev, REG_STEPCONFIG(i), ++ stepconfig | STEPCONFIG_INP(channels)); ++ tiadc_writel(adc_dev, REG_STEPDELAY(i), ++ STEPCONFIG_OPENDLY); ++ channels++; ++ } ++ tiadc_writel(adc_dev, REG_SE, STPENB_STEPENB); ++} ++ ++static int tiadc_channel_init(struct iio_dev *indio_dev, int channels) ++{ ++ struct iio_chan_spec *chan_array; ++ int i; ++ ++ indio_dev->num_channels = channels; ++ chan_array = kcalloc(indio_dev->num_channels, ++ sizeof(struct iio_chan_spec), GFP_KERNEL); ++ ++ if (chan_array == NULL) ++ return -ENOMEM; ++ ++ for (i = 0; i < (indio_dev->num_channels); i++) { ++ struct iio_chan_spec *chan = chan_array + i; ++ chan->type = IIO_VOLTAGE; ++ chan->indexed = 1; ++ chan->channel = i; ++ chan->info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT; ++ } ++ ++ indio_dev->channels = chan_array; ++ ++ return indio_dev->num_channels; ++} ++ ++static void tiadc_channels_remove(struct iio_dev *indio_dev) ++{ ++ kfree(indio_dev->channels); ++} ++ ++static int tiadc_read_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, ++ int *val, int *val2, long mask) ++{ ++ struct tiadc_device *adc_dev = iio_priv(indio_dev); ++ int i; ++ unsigned int fifo1count, readx1; ++ ++ /* ++ * When the sub-system is first enabled, ++ * the sequencer will always start with the ++ * lowest step (1) and continue until step (16). ++ * For ex: If we have enabled 4 ADC channels and ++ * currently use only 1 out of them, the ++ * sequencer still configures all the 4 steps, ++ * leading to 3 unwanted data. ++ * Hence we need to flush out this data. ++ */ ++ ++ fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); ++ for (i = 0; i < fifo1count; i++) { ++ readx1 = tiadc_readl(adc_dev, REG_FIFO1); ++ if (i == chan->channel) ++ *val = readx1 & 0xfff; ++ } ++ tiadc_writel(adc_dev, REG_SE, STPENB_STEPENB); ++ ++ return IIO_VAL_INT; ++} ++ ++static const struct iio_info tiadc_info = { ++ .read_raw = &tiadc_read_raw, ++}; ++ ++static int __devinit tiadc_probe(struct platform_device *pdev) ++{ ++ struct iio_dev *indio_dev; ++ struct tiadc_device *adc_dev; ++ struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; ++ struct mfd_tscadc_board *pdata; ++ int err; ++ ++ pdata = tscadc_dev->dev->platform_data; ++ if (!pdata || !pdata->adc_init) { ++ dev_err(&pdev->dev, "Could not find platform data\n"); ++ return -EINVAL; ++ } ++ ++ indio_dev = iio_device_alloc(sizeof(struct tiadc_device)); ++ if (indio_dev == NULL) { ++ dev_err(&pdev->dev, "failed to allocate iio device\n"); ++ err = -ENOMEM; ++ goto err_ret; ++ } ++ adc_dev = iio_priv(indio_dev); ++ ++ adc_dev->mfd_tscadc = tscadc_dev; ++ adc_dev->channels = pdata->adc_init->adc_channels; ++ ++ indio_dev->dev.parent = &pdev->dev; ++ indio_dev->name = dev_name(&pdev->dev); ++ indio_dev->modes = INDIO_DIRECT_MODE; ++ indio_dev->info = &tiadc_info; ++ ++ tiadc_step_config(adc_dev); ++ ++ err = tiadc_channel_init(indio_dev, adc_dev->channels); ++ if (err < 0) ++ goto err_free_device; ++ ++ err = iio_device_register(indio_dev); ++ if (err) ++ goto err_free_channels; ++ ++ platform_set_drvdata(pdev, indio_dev); ++ ++ return 0; ++ ++err_free_channels: ++ tiadc_channels_remove(indio_dev); ++err_free_device: ++ iio_device_free(indio_dev); ++err_ret: ++ return err; ++} ++ ++static int __devexit tiadc_remove(struct platform_device *pdev) ++{ ++ struct iio_dev *indio_dev = platform_get_drvdata(pdev); ++ ++ iio_device_unregister(indio_dev); ++ tiadc_channels_remove(indio_dev); ++ ++ iio_device_free(indio_dev); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int tiadc_suspend(struct device *dev) ++{ ++ struct iio_dev *indio_dev = dev_get_drvdata(dev); ++ struct tiadc_device *adc_dev = iio_priv(indio_dev); ++ struct ti_tscadc_dev *tscadc_dev = dev->platform_data; ++ unsigned int idle; ++ ++ if (!device_may_wakeup(tscadc_dev->dev)) { ++ idle = tiadc_readl(adc_dev, REG_CTRL); ++ idle &= ~(CNTRLREG_TSCSSENB); ++ tiadc_writel(adc_dev, REG_CTRL, (idle | ++ CNTRLREG_POWERDOWN)); ++ } ++ ++ return 0; ++} ++ ++static int tiadc_resume(struct device *dev) ++{ ++ struct iio_dev *indio_dev = dev_get_drvdata(dev); ++ struct tiadc_device *adc_dev = iio_priv(indio_dev); ++ unsigned int restore; ++ ++ /* Make sure ADC is powered up */ ++ restore = tiadc_readl(adc_dev, REG_CTRL); ++ restore &= ~(CNTRLREG_POWERDOWN); ++ tiadc_writel(adc_dev, REG_CTRL, restore); ++ ++ tiadc_step_config(adc_dev); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops tiadc_pm_ops = { ++ .suspend = tiadc_suspend, ++ .resume = tiadc_resume, ++}; ++#define TIADC_PM_OPS (&tiadc_pm_ops) ++#else ++#define TIADC_PM_OPS NULL ++#endif ++ ++static struct platform_driver tiadc_driver = { ++ .driver = { ++ .name = "tiadc", ++ .owner = THIS_MODULE, ++ .pm = TIADC_PM_OPS, ++ }, ++ .probe = tiadc_probe, ++ .remove = __devexit_p(tiadc_remove), ++}; ++ ++module_platform_driver(tiadc_driver); ++ ++MODULE_DESCRIPTION("TI ADC controller driver"); ++MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c +index d812be4..e947dd8 100644 +--- a/drivers/mfd/ti_am335x_tscadc.c ++++ b/drivers/mfd/ti_am335x_tscadc.c +@@ -25,6 +25,7 @@ + + #include <linux/mfd/ti_am335x_tscadc.h> + #include <linux/input/ti_am335x_tsc.h> ++#include <linux/platform_data/ti_am335x_adc.h> + + static unsigned int tscadc_readl(struct ti_tscadc_dev *tsadc, unsigned int reg) + { +@@ -67,14 +68,23 @@ static int __devinit ti_tscadc_probe(struct platform_device *pdev) + int irq; + int err, ctrl; + int clk_value, clock_rate; +- int tsc_wires; ++ int tsc_wires, adc_channels = 0, total_channels; + + if (!pdata) { + dev_err(&pdev->dev, "Could not find platform data\n"); + return -EINVAL; + } + ++ if (pdata->adc_init) ++ adc_channels = pdata->adc_init->adc_channels; ++ + tsc_wires = pdata->tsc_init->wires; ++ total_channels = tsc_wires + adc_channels; ++ ++ if (total_channels > 8) { ++ dev_err(&pdev->dev, "Number of i/p channels more than 8\n"); ++ return -EINVAL; ++ } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { +@@ -172,6 +182,12 @@ static int __devinit ti_tscadc_probe(struct platform_device *pdev) + cell->platform_data = tscadc; + cell->pdata_size = sizeof(*tscadc); + ++ /* ADC Cell */ ++ cell = &tscadc->cells[ADC_CELL]; ++ cell->name = "tiadc"; ++ cell->platform_data = tscadc; ++ cell->pdata_size = sizeof(*tscadc); ++ + err = mfd_add_devices(&pdev->dev, pdev->id, tscadc->cells, + TSCADC_CELLS, NULL, 0, NULL); + if (err < 0) +diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h +index fc18b2e..c79ad5d 100644 +--- a/include/linux/mfd/ti_am335x_tscadc.h ++++ b/include/linux/mfd/ti_am335x_tscadc.h +@@ -120,15 +120,19 @@ + + #define ADC_CLK 3000000 + #define MAX_CLK_DIV 7 ++#define TOTAL_STEPS 16 ++#define TOTAL_CHANNELS 8 + +-#define TSCADC_CELLS 1 ++#define TSCADC_CELLS 2 + + enum tscadc_cells { + TSC_CELL, ++ ADC_CELL, + }; + + struct mfd_tscadc_board { + struct tsc_data *tsc_init; ++ struct adc_data *adc_init; + }; + + struct ti_tscadc_dev { +@@ -140,6 +144,9 @@ struct ti_tscadc_dev { + + /* tsc device */ + struct titsc *tsc; ++ ++ /* adc device */ ++ struct adc_device *adc; + }; + + #endif +diff --git a/include/linux/platform_data/ti_am335x_adc.h b/include/linux/platform_data/ti_am335x_adc.h +new file mode 100644 +index 0000000..e41d583 +--- /dev/null ++++ b/include/linux/platform_data/ti_am335x_adc.h +@@ -0,0 +1,14 @@ ++#ifndef __LINUX_TI_AM335X_ADC_H ++#define __LINUX_TI_AM335X_ADC_H ++ ++/** ++ * struct adc_data ADC Input information ++ * @adc_channels: Number of analog inputs ++ * available for ADC. ++ */ ++ ++struct adc_data { ++ unsigned int adc_channels; ++}; ++ ++#endif diff --git a/patches/linux-3.7-rc6/0053-input-ti_am335x_tsc-Make-steps-enable-configurable.patch b/patches/linux-3.7-rc6/0053-input-ti_am335x_tsc-Make-steps-enable-configurable.patch new file mode 100644 index 0000000..cc791d4 --- /dev/null +++ b/patches/linux-3.7-rc6/0053-input-ti_am335x_tsc-Make-steps-enable-configurable.patch @@ -0,0 +1,74 @@ +From c2e4f935c7eb7e48e81eee2f11582ea686e9199a Mon Sep 17 00:00:00 2001 +From: "Patil, Rachna" <rachna@ti.com> +Date: Mon, 22 Oct 2012 10:15:16 +0000 +Subject: [PATCH] input: ti_am335x_tsc: Make steps enable configurable + +Current code has hard coded value written to +step enable bits. Now the bits are updated based +on how many steps are needed to be configured got +from platform data. + +The user needs to take care not to exceed +the count more than 16. While using ADC and TSC +one should take care to set this parameter correctly. + +Signed-off-by: Patil, Rachna <rachna@ti.com> +--- + drivers/input/touchscreen/ti_am335x_tsc.c | 10 ++++++++-- + include/linux/mfd/ti_am335x_tscadc.h | 1 - + 2 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c +index 7a18a8a..4369224 100644 +--- a/drivers/input/touchscreen/ti_am335x_tsc.c ++++ b/drivers/input/touchscreen/ti_am335x_tsc.c +@@ -39,6 +39,7 @@ struct titsc { + unsigned int irq; + unsigned int wires; + unsigned int x_plate_resistance; ++ unsigned int enable_bits; + bool pen_down; + int steps_to_configure; + }; +@@ -57,6 +58,7 @@ static void titsc_writel(struct titsc *tsc, unsigned int reg, + static void titsc_step_config(struct titsc *ts_dev) + { + unsigned int config; ++ unsigned int stepenable = 0; + int i, total_steps; + + /* Configure the Step registers */ +@@ -128,7 +130,11 @@ static void titsc_step_config(struct titsc *ts_dev) + titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2), + STEPCONFIG_OPENDLY); + +- titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC); ++ for (i = 0; i <= (total_steps + 2); i++) ++ stepenable |= 1 << i; ++ ts_dev->enable_bits = stepenable; ++ ++ titsc_writel(ts_dev, REG_SE, ts_dev->enable_bits); + } + + static void titsc_read_coordinates(struct titsc *ts_dev, +@@ -250,7 +256,7 @@ static irqreturn_t titsc_irq(int irq, void *dev) + + titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); + +- titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC); ++ titsc_writel(ts_dev, REG_SE, ts_dev->enable_bits); + return IRQ_HANDLED; + } + +diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h +index c79ad5d..23e4f33 100644 +--- a/include/linux/mfd/ti_am335x_tscadc.h ++++ b/include/linux/mfd/ti_am335x_tscadc.h +@@ -47,7 +47,6 @@ + #define STEPENB_MASK (0x1FFFF << 0) + #define STEPENB(val) ((val) << 0) + #define STPENB_STEPENB STEPENB(0x1FFFF) +-#define STPENB_STEPENB_TC STEPENB(0x1FFF) + + /* IRQ enable */ + #define IRQENB_HW_PEN BIT(0) diff --git a/patches/linux-3.7-rc6/0054-input-ti_am335x_tsc-Order-of-TSC-wires-connect-made-.patch b/patches/linux-3.7-rc6/0054-input-ti_am335x_tsc-Order-of-TSC-wires-connect-made-.patch new file mode 100644 index 0000000..0f7105a --- /dev/null +++ b/patches/linux-3.7-rc6/0054-input-ti_am335x_tsc-Order-of-TSC-wires-connect-made-.patch @@ -0,0 +1,329 @@ +From 27f22a592f264d221ecd8ddc1dc8f7d49ea4108a Mon Sep 17 00:00:00 2001 +From: "Patil, Rachna" <rachna@ti.com> +Date: Mon, 22 Oct 2012 10:15:17 +0000 +Subject: [PATCH] input: ti_am335x_tsc: Order of TSC wires connect, made + configurable + +The driver expected touchscreen wires(XP,XN,YP,YN) +to be connected in a particular order. +Making changes to accept this as platform data. + +Signed-off-by: Patil, Rachna <rachna@ti.com> +--- + drivers/input/touchscreen/ti_am335x_tsc.c | 156 ++++++++++++++++++++++++++--- + include/linux/input/ti_am335x_tsc.h | 12 +++ + include/linux/mfd/ti_am335x_tscadc.h | 10 +- + 3 files changed, 159 insertions(+), 19 deletions(-) + +diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c +index 4369224..6a817a8 100644 +--- a/drivers/input/touchscreen/ti_am335x_tsc.c ++++ b/drivers/input/touchscreen/ti_am335x_tsc.c +@@ -33,6 +33,17 @@ + #define SEQ_SETTLE 275 + #define MAX_12BIT ((1 << 12) - 1) + ++/* ++ * Refer to function regbit_map() to ++ * map the values in the matrix. ++ */ ++static int config[4][4] = { ++ {1, 0, 1, 0}, ++ {2, 3, 2, 3}, ++ {4, 5, 4, 5}, ++ {0, 6, 0, 6} ++}; ++ + struct titsc { + struct input_dev *input; + struct ti_tscadc_dev *mfd_tscadc; +@@ -42,6 +53,9 @@ struct titsc { + unsigned int enable_bits; + bool pen_down; + int steps_to_configure; ++ int config_inp[20]; ++ int bit_xp, bit_xn, bit_yp, bit_yn; ++ int inp_xp, inp_xn, inp_yp, inp_yn; + }; + + static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) +@@ -55,6 +69,107 @@ static void titsc_writel(struct titsc *tsc, unsigned int reg, + writel(val, tsc->mfd_tscadc->tscadc_base + reg); + } + ++/* ++ * Each of the analog lines are mapped ++ * with one or two register bits, ++ * which can be either pulled high/low ++ * depending on the value to be read. ++ */ ++static int regbit_map(int val) ++{ ++ int map_bits = 0; ++ ++ switch (val) { ++ case 1: ++ map_bits = XPP; ++ break; ++ case 2: ++ map_bits = XNP; ++ break; ++ case 3: ++ map_bits = XNN; ++ break; ++ case 4: ++ map_bits = YPP; ++ break; ++ case 5: ++ map_bits = YPN; ++ break; ++ case 6: ++ map_bits = YNN; ++ break; ++ } ++ ++ return map_bits; ++} ++ ++static int titsc_config_wires(struct titsc *ts_dev) ++{ ++ int analog_line[10], wire_order[10]; ++ int i, temp_bits, err; ++ ++ for (i = 0; i < 4; i++) { ++ /* ++ * Get the order in which TSC wires are attached ++ * w.r.t. each of the analog input lines on the EVM. ++ */ ++ analog_line[i] = ts_dev->config_inp[i] & 0xF0; ++ analog_line[i] = analog_line[i] >> 4; ++ ++ wire_order[i] = ts_dev->config_inp[i] & 0x0F; ++ } ++ ++ for (i = 0; i < 4; i++) { ++ switch (wire_order[i]) { ++ case 0: ++ temp_bits = config[analog_line[i]][0]; ++ if (temp_bits == 0) { ++ err = -EINVAL; ++ goto ret; ++ } else { ++ ts_dev->bit_xp = regbit_map(temp_bits); ++ ts_dev->inp_xp = analog_line[i]; ++ break; ++ } ++ case 1: ++ temp_bits = config[analog_line[i]][1]; ++ if (temp_bits == 0) { ++ err = -EINVAL; ++ goto ret; ++ } else { ++ ts_dev->bit_xn = regbit_map(temp_bits); ++ ts_dev->inp_xn = analog_line[i]; ++ break; ++ } ++ case 2: ++ temp_bits = config[analog_line[i]][2]; ++ if (temp_bits == 0) { ++ err = -EINVAL; ++ goto ret; ++ } else { ++ ts_dev->bit_yp = regbit_map(temp_bits); ++ ts_dev->inp_yp = analog_line[i]; ++ break; ++ } ++ case 3: ++ temp_bits = config[analog_line[i]][3]; ++ if (temp_bits == 0) { ++ err = -EINVAL; ++ goto ret; ++ } else { ++ ts_dev->bit_yn = regbit_map(temp_bits); ++ ts_dev->inp_yn = analog_line[i]; ++ break; ++ } ++ } ++ } ++ ++ return 0; ++ ++ret: ++ return err; ++} ++ + static void titsc_step_config(struct titsc *ts_dev) + { + unsigned int config; +@@ -65,18 +180,18 @@ static void titsc_step_config(struct titsc *ts_dev) + total_steps = 2 * ts_dev->steps_to_configure; + + config = STEPCONFIG_MODE_HWSYNC | +- STEPCONFIG_AVG_16 | STEPCONFIG_XPP; ++ STEPCONFIG_AVG_16 | ts_dev->bit_xp; + switch (ts_dev->wires) { + case 4: +- config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; ++ config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn; + break; + case 5: +- config |= STEPCONFIG_YNN | +- STEPCONFIG_INP_AN4 | STEPCONFIG_XNN | +- STEPCONFIG_YPP; ++ config |= ts_dev->bit_yn | ++ STEPCONFIG_INP_AN4 | ts_dev->bit_xn | ++ ts_dev->bit_yp; + break; + case 8: +- config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; ++ config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn; + break; + } + +@@ -87,18 +202,18 @@ static void titsc_step_config(struct titsc *ts_dev) + + config = 0; + config = STEPCONFIG_MODE_HWSYNC | +- STEPCONFIG_AVG_16 | STEPCONFIG_YNN | ++ STEPCONFIG_AVG_16 | ts_dev->bit_yn | + STEPCONFIG_INM_ADCREFM | STEPCONFIG_FIFO1; + switch (ts_dev->wires) { + case 4: +- config |= STEPCONFIG_YPP; ++ config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp); + break; + case 5: +- config |= STEPCONFIG_XPP | STEPCONFIG_INP_AN4 | +- STEPCONFIG_XNP | STEPCONFIG_YPN; ++ config |= ts_dev->bit_xp | STEPCONFIG_INP_AN4 | ++ ts_dev->bit_xn | ts_dev->bit_yp; + break; + case 8: +- config |= STEPCONFIG_YPP; ++ config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp); + break; + } + +@@ -109,9 +224,9 @@ static void titsc_step_config(struct titsc *ts_dev) + + config = 0; + /* Charge step configuration */ +- config = STEPCONFIG_XPP | STEPCONFIG_YNN | ++ config = ts_dev->bit_xp | ts_dev->bit_yn | + STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR | +- STEPCHARGE_INM_AN1 | STEPCHARGE_INP_AN1; ++ STEPCHARGE_INM_AN1 | STEPCHARGE_INP(ts_dev->inp_yp); + + titsc_writel(ts_dev, REG_CHARGECONFIG, config); + titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY); +@@ -119,13 +234,14 @@ static void titsc_step_config(struct titsc *ts_dev) + config = 0; + /* Configure to calculate pressure */ + config = STEPCONFIG_MODE_HWSYNC | +- STEPCONFIG_AVG_16 | STEPCONFIG_YPP | +- STEPCONFIG_XNN | STEPCONFIG_INM_ADCREFM; ++ STEPCONFIG_AVG_16 | ts_dev->bit_yp | ++ ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM | ++ STEPCONFIG_INP(ts_dev->inp_xp); + titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 1), config); + titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 1), + STEPCONFIG_OPENDLY); + +- config |= STEPCONFIG_INP_AN3 | STEPCONFIG_FIFO1; ++ config |= STEPCONFIG_INP(ts_dev->inp_yn) | STEPCONFIG_FIFO1; + titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 2), config); + titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2), + STEPCONFIG_OPENDLY); +@@ -295,6 +411,8 @@ static int __devinit titsc_probe(struct platform_device *pdev) + ts_dev->wires = pdata->tsc_init->wires; + ts_dev->x_plate_resistance = pdata->tsc_init->x_plate_resistance; + ts_dev->steps_to_configure = pdata->tsc_init->steps_to_configure; ++ memcpy(ts_dev->config_inp, pdata->tsc_init->wire_config, ++ sizeof(pdata->tsc_init->wire_config)); + + err = request_irq(ts_dev->irq, titsc_irq, + 0, pdev->dev.driver->name, ts_dev); +@@ -304,6 +422,11 @@ static int __devinit titsc_probe(struct platform_device *pdev) + } + + titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); ++ err = titsc_config_wires(ts_dev); ++ if (err) { ++ dev_err(&pdev->dev, "wrong i/p wire configuration\n"); ++ goto err_free_irq; ++ } + titsc_step_config(ts_dev); + titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure); + +@@ -373,6 +496,7 @@ static int titsc_resume(struct device *dev) + 0x00); + titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); + } ++ titsc_config_wires(ts_dev); + titsc_step_config(ts_dev); + titsc_writel(ts_dev, REG_FIFO0THR, + ts_dev->steps_to_configure); +diff --git a/include/linux/input/ti_am335x_tsc.h b/include/linux/input/ti_am335x_tsc.h +index 49269a2..6a66b4d 100644 +--- a/include/linux/input/ti_am335x_tsc.h ++++ b/include/linux/input/ti_am335x_tsc.h +@@ -12,12 +12,24 @@ + * A step configured to read a single + * co-ordinate value, can be applied + * more number of times for better results. ++ * @wire_config: Different EVM's could have a different order ++ * for connecting wires on touchscreen. ++ * We need to provide an 8 bit number where in ++ * the 1st four bits represent the analog lines ++ * and the next 4 bits represent positive/ ++ * negative terminal on that input line. ++ * Notations to represent the input lines and ++ * terminals resoectively is as follows: ++ * AIN0 = 0, AIN1 = 1 and so on till AIN7 = 7. ++ * XP = 0, XN = 1, YP = 2, YN = 3. ++ * + */ + + struct tsc_data { + int wires; + int x_plate_resistance; + int steps_to_configure; ++ int wire_config[10]; + }; + + #endif +diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h +index 23e4f33..9624fea 100644 +--- a/include/linux/mfd/ti_am335x_tscadc.h ++++ b/include/linux/mfd/ti_am335x_tscadc.h +@@ -72,8 +72,6 @@ + #define STEPCONFIG_INM_ADCREFM STEPCONFIG_INM(8) + #define STEPCONFIG_INP_MASK (0xF << 19) + #define STEPCONFIG_INP(val) ((val) << 19) +-#define STEPCONFIG_INP_AN2 STEPCONFIG_INP(2) +-#define STEPCONFIG_INP_AN3 STEPCONFIG_INP(3) + #define STEPCONFIG_INP_AN4 STEPCONFIG_INP(4) + #define STEPCONFIG_INP_ADCREFM STEPCONFIG_INP(8) + #define STEPCONFIG_FIFO1 BIT(26) +@@ -95,7 +93,6 @@ + #define STEPCHARGE_INM_AN1 STEPCHARGE_INM(1) + #define STEPCHARGE_INP_MASK (0xF << 19) + #define STEPCHARGE_INP(val) ((val) << 19) +-#define STEPCHARGE_INP_AN1 STEPCHARGE_INP(1) + #define STEPCHARGE_RFM_MASK (3 << 23) + #define STEPCHARGE_RFM(val) ((val) << 23) + #define STEPCHARGE_RFM_XNUR STEPCHARGE_RFM(1) +@@ -117,6 +114,13 @@ + #define CNTRLREG_8WIRE CNTRLREG_AFE_CTRL(3) + #define CNTRLREG_TSCENB BIT(7) + ++#define XPP STEPCONFIG_XPP ++#define XNP STEPCONFIG_XNP ++#define XNN STEPCONFIG_XNN ++#define YPP STEPCONFIG_YPP ++#define YPN STEPCONFIG_YPN ++#define YNN STEPCONFIG_YNN ++ + #define ADC_CLK 3000000 + #define MAX_CLK_DIV 7 + #define TOTAL_STEPS 16 diff --git a/patches/linux-3.7-rc6/0055-input-ti_am335x_tsc-Add-variance-filters.patch b/patches/linux-3.7-rc6/0055-input-ti_am335x_tsc-Add-variance-filters.patch new file mode 100644 index 0000000..4be6c7d --- /dev/null +++ b/patches/linux-3.7-rc6/0055-input-ti_am335x_tsc-Add-variance-filters.patch @@ -0,0 +1,75 @@ +From 18d663634d89727e277e5055af890bbfa13eeffc Mon Sep 17 00:00:00 2001 +From: "Patil, Rachna" <rachna@ti.com> +Date: Mon, 22 Oct 2012 10:15:18 +0000 +Subject: [PATCH] input: ti_am335x_tsc: Add variance filters + +Only fine tuning variance present in tslib utility +does not help in removing all the wanted ADC noise. +This logic of filtering is necessary to get this +touchscreen to work finely. + +Signed-off-by: Patil, Rachna <rachna@ti.com> +--- + drivers/input/touchscreen/ti_am335x_tsc.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c +index 6a817a8..7a26810 100644 +--- a/drivers/input/touchscreen/ti_am335x_tsc.c ++++ b/drivers/input/touchscreen/ti_am335x_tsc.c +@@ -32,6 +32,8 @@ + #define ADCFSM_STEPID 0x10 + #define SEQ_SETTLE 275 + #define MAX_12BIT ((1 << 12) - 1) ++#define TSCADC_DELTA_X 15 ++#define TSCADC_DELTA_Y 15 + + /* + * Refer to function regbit_map() to +@@ -51,6 +53,8 @@ struct titsc { + unsigned int wires; + unsigned int x_plate_resistance; + unsigned int enable_bits; ++ unsigned int bckup_x; ++ unsigned int bckup_y; + bool pen_down; + int steps_to_configure; + int config_inp[20]; +@@ -309,12 +313,18 @@ static irqreturn_t titsc_irq(int irq, void *dev) + unsigned int z1, z2, z; + unsigned int fsm; + unsigned int fifo1count, fifo0count; ++ unsigned int diffx = 0, diffy = 0; + int i; + + status = titsc_readl(ts_dev, REG_IRQSTATUS); + if (status & IRQENB_FIFO0THRES) { + titsc_read_coordinates(ts_dev, &x, &y); + ++ diffx = abs(x - (ts_dev->bckup_x)); ++ diffy = abs(y - (ts_dev->bckup_y)); ++ ts_dev->bckup_x = x; ++ ts_dev->bckup_y = y; ++ + z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff; + z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff; + +@@ -338,7 +348,8 @@ static irqreturn_t titsc_irq(int irq, void *dev) + z /= z1; + z = (z + 2047) >> 12; + +- if (z <= MAX_12BIT) { ++ if ((diffx < TSCADC_DELTA_X) && ++ (diffy < TSCADC_DELTA_Y) && (z <= MAX_12BIT)) { + input_report_abs(input_dev, ABS_X, x); + input_report_abs(input_dev, ABS_Y, y); + input_report_abs(input_dev, ABS_PRESSURE, z); +@@ -361,6 +372,8 @@ static irqreturn_t titsc_irq(int irq, void *dev) + fsm = titsc_readl(ts_dev, REG_ADCFSM); + if (fsm == ADCFSM_STEPID) { + ts_dev->pen_down = false; ++ ts_dev->bckup_x = 0; ++ ts_dev->bckup_y = 0; + input_report_key(input_dev, BTN_TOUCH, 0); + input_report_abs(input_dev, ABS_PRESSURE, 0); + input_sync(input_dev); diff --git a/patches/linux-3.7-rc6/0056-ti_tscadc-Update-with-IIO-map-interface-deal-with-pa.patch b/patches/linux-3.7-rc6/0056-ti_tscadc-Update-with-IIO-map-interface-deal-with-pa.patch new file mode 100644 index 0000000..d0ebf97 --- /dev/null +++ b/patches/linux-3.7-rc6/0056-ti_tscadc-Update-with-IIO-map-interface-deal-with-pa.patch @@ -0,0 +1,183 @@ +From 8f4be87c38d30e43f4e83fd104a64e642589f9b2 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Sat, 13 Oct 2012 16:37:24 +0300 +Subject: [PATCH] ti_tscadc: Update with IIO map interface & deal with partial + activation + +Add an IIO map interface that consumers can use. +While we're here fix the mfd device in the case where a subdevice +might not be activated. +--- + drivers/iio/adc/ti_am335x_adc.c | 53 ++++++++++++++++++++++++++++------ + drivers/mfd/ti_am335x_tscadc.c | 30 +++++++++++++------ + include/linux/mfd/ti_am335x_tscadc.h | 8 ++--- + 3 files changed, 68 insertions(+), 23 deletions(-) + +diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c +index 02a43c8..d48fd79 100644 +--- a/drivers/iio/adc/ti_am335x_adc.c ++++ b/drivers/iio/adc/ti_am335x_adc.c +@@ -20,8 +20,9 @@ + #include <linux/slab.h> + #include <linux/interrupt.h> + #include <linux/platform_device.h> +-#include <linux/io.h> + #include <linux/iio/iio.h> ++#include <linux/iio/machine.h> ++#include <linux/iio/driver.h> + + #include <linux/mfd/ti_am335x_tscadc.h> + #include <linux/platform_data/ti_am335x_adc.h> +@@ -29,6 +30,8 @@ + struct tiadc_device { + struct ti_tscadc_dev *mfd_tscadc; + int channels; ++ char *buf; ++ struct iio_map *map; + }; + + static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg) +@@ -75,25 +78,57 @@ static void tiadc_step_config(struct tiadc_device *adc_dev) + static int tiadc_channel_init(struct iio_dev *indio_dev, int channels) + { + struct iio_chan_spec *chan_array; +- int i; +- +- indio_dev->num_channels = channels; +- chan_array = kcalloc(indio_dev->num_channels, +- sizeof(struct iio_chan_spec), GFP_KERNEL); ++ struct iio_chan_spec *chan; ++ char *s; ++ int i, len, size, ret; + ++ size = indio_dev->num_channels * (sizeof(struct iio_chan_spec) + 6); ++ chan_array = kzalloc(size, GFP_KERNEL); + if (chan_array == NULL) + return -ENOMEM; + +- for (i = 0; i < (indio_dev->num_channels); i++) { +- struct iio_chan_spec *chan = chan_array + i; ++ /* buffer space is after the array */ ++ s = (char *)(chan_array + indio_dev->num_channels); ++ chan = chan_array; ++ for (i = 0; i < indio_dev->num_channels; i++, chan++, s += len + 1) { ++ ++ len = sprintf(s, "AIN%d", i); ++ + chan->type = IIO_VOLTAGE; + chan->indexed = 1; + chan->channel = i; +- chan->info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT; ++ chan->datasheet_name = s; ++ chan->scan_type.sign = 'u'; ++ chan->scan_type.realbits = 12; ++ chan->scan_type.storagebits = 32; ++ chan->scan_type.shift = 0; + } + + indio_dev->channels = chan_array; + ++ size = (indio_dev->num_channels + 1) * sizeof(struct iio_map); ++ adc_dev->map = kzalloc(size, GFP_KERNEL); ++ if (adc_dev->map == NULL) { ++ kfree(chan_array); ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < indio_dev->num_channels; i++) { ++ adc_dev->map[i].adc_channel_label = chan_array[i].datasheet_name; ++ adc_dev->map[i].consumer_dev_name = "any"; ++ adc_dev->map[i].consumer_channel = chan_array[i].datasheet_name; ++ } ++ adc_dev->map[i].adc_channel_label = NULL; ++ adc_dev->map[i].consumer_dev_name = NULL; ++ adc_dev->map[i].consumer_channel = NULL; ++ ++ ret = iio_map_array_register(indio_dev, adc_dev->map); ++ if (ret != 0) { ++ kfree(adc_dev->map); ++ kfree(chan_array); ++ return -ENOMEM; ++ } ++ + return indio_dev->num_channels; + } + +diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c +index e947dd8..cbb8b70c 100644 +--- a/drivers/mfd/ti_am335x_tscadc.c ++++ b/drivers/mfd/ti_am335x_tscadc.c +@@ -176,26 +176,38 @@ static int __devinit ti_tscadc_probe(struct platform_device *pdev) + ctrl |= CNTRLREG_TSCSSENB; + tscadc_writel(tscadc, REG_CTRL, ctrl); + ++ tscadc->used_cells = 0; ++ tscadc->tsc_cell = -1; ++ tscadc->adc_cell = -1; ++ + /* TSC Cell */ +- cell = &tscadc->cells[TSC_CELL]; +- cell->name = "tsc"; +- cell->platform_data = tscadc; +- cell->pdata_size = sizeof(*tscadc); ++ if (tsc_wires > 0) { ++ tscadc->tsc_cell = tscadc->used_cells; ++ cell = &tscadc->cells[tscadc->used_cells++]; ++ cell->name = "tsc"; ++ cell->platform_data = tscadc; ++ cell->pdata_size = sizeof(*tscadc); ++ } + + /* ADC Cell */ +- cell = &tscadc->cells[ADC_CELL]; +- cell->name = "tiadc"; +- cell->platform_data = tscadc; +- cell->pdata_size = sizeof(*tscadc); ++ if (adc_channels > 0) { ++ tscadc->adc_cell = tscadc->used_cells; ++ cell = &tscadc->cells[tscadc->used_cells++]; ++ cell->name = "tiadc"; ++ cell->platform_data = tscadc; ++ cell->pdata_size = sizeof(*tscadc); ++ } + + err = mfd_add_devices(&pdev->dev, pdev->id, tscadc->cells, +- TSCADC_CELLS, NULL, 0, NULL); ++ tscadc->used_cells, NULL, 0, NULL); + if (err < 0) + goto err_disable_clk; + + device_init_wakeup(&pdev->dev, true); + platform_set_drvdata(pdev, tscadc); + ++ dev_info(&pdev->dev, "Initialized OK.\n"); ++ + return 0; + + err_disable_clk: +diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h +index 9624fea..50a245f 100644 +--- a/include/linux/mfd/ti_am335x_tscadc.h ++++ b/include/linux/mfd/ti_am335x_tscadc.h +@@ -128,11 +128,6 @@ + + #define TSCADC_CELLS 2 + +-enum tscadc_cells { +- TSC_CELL, +- ADC_CELL, +-}; +- + struct mfd_tscadc_board { + struct tsc_data *tsc_init; + struct adc_data *adc_init; +@@ -143,6 +138,9 @@ struct ti_tscadc_dev { + struct regmap *regmap_tscadc; + void __iomem *tscadc_base; + int irq; ++ int used_cells; /* 0-2 */ ++ int tsc_cell; /* -1 if not used */ ++ int adc_cell; /* -1 if not used */ + struct mfd_cell cells[TSCADC_CELLS]; + + /* tsc device */ diff --git a/patches/linux-3.7-rc6/0057-ti_tscadc-Match-mfd-sub-devices-to-regmap-interface.patch b/patches/linux-3.7-rc6/0057-ti_tscadc-Match-mfd-sub-devices-to-regmap-interface.patch new file mode 100644 index 0000000..645adc4 --- /dev/null +++ b/patches/linux-3.7-rc6/0057-ti_tscadc-Match-mfd-sub-devices-to-regmap-interface.patch @@ -0,0 +1,184 @@ +From e2ca20cc059c217cd78963a77189004645de55c7 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Fri, 26 Oct 2012 14:01:05 +0300 +Subject: [PATCH] ti_tscadc: Match mfd sub devices to regmap interface + +--- + drivers/iio/adc/ti_am335x_adc.c | 27 +++++++++++++++++++-------- + drivers/input/touchscreen/ti_am335x_tsc.c | 16 +++++++++++++--- + drivers/mfd/ti_am335x_tscadc.c | 7 +++++-- + 3 files changed, 37 insertions(+), 13 deletions(-) + +diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c +index d48fd79..5f325c1 100644 +--- a/drivers/iio/adc/ti_am335x_adc.c ++++ b/drivers/iio/adc/ti_am335x_adc.c +@@ -23,7 +23,9 @@ + #include <linux/iio/iio.h> + #include <linux/iio/machine.h> + #include <linux/iio/driver.h> ++#include <linux/regmap.h> + ++#include <linux/io.h> + #include <linux/mfd/ti_am335x_tscadc.h> + #include <linux/platform_data/ti_am335x_adc.h> + +@@ -36,13 +38,17 @@ struct tiadc_device { + + static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg) + { +- return readl(adc->mfd_tscadc->tscadc_base + reg); ++ unsigned int val; ++ ++ val = (unsigned int)-1; ++ regmap_read(adc->mfd_tscadc->regmap_tscadc, reg, &val); ++ return val; + } + + static void tiadc_writel(struct tiadc_device *adc, unsigned int reg, + unsigned int val) + { +- writel(val, adc->mfd_tscadc->tscadc_base + reg); ++ regmap_write(adc->mfd_tscadc->regmap_tscadc, reg, val); + } + + static void tiadc_step_config(struct tiadc_device *adc_dev) +@@ -75,22 +81,24 @@ static void tiadc_step_config(struct tiadc_device *adc_dev) + tiadc_writel(adc_dev, REG_SE, STPENB_STEPENB); + } + +-static int tiadc_channel_init(struct iio_dev *indio_dev, int channels) ++static int tiadc_channel_init(struct iio_dev *indio_dev, ++ struct tiadc_device *adc_dev) + { + struct iio_chan_spec *chan_array; + struct iio_chan_spec *chan; + char *s; + int i, len, size, ret; ++ int channels = adc_dev->channels; + +- size = indio_dev->num_channels * (sizeof(struct iio_chan_spec) + 6); ++ size = channels * (sizeof(struct iio_chan_spec) + 6); + chan_array = kzalloc(size, GFP_KERNEL); + if (chan_array == NULL) + return -ENOMEM; + + /* buffer space is after the array */ +- s = (char *)(chan_array + indio_dev->num_channels); ++ s = (char *)(chan_array + channels); + chan = chan_array; +- for (i = 0; i < indio_dev->num_channels; i++, chan++, s += len + 1) { ++ for (i = 0; i < channels; i++, chan++, s += len + 1) { + + len = sprintf(s, "AIN%d", i); + +@@ -105,8 +113,9 @@ static int tiadc_channel_init(struct iio_dev *indio_dev, int channels) + } + + indio_dev->channels = chan_array; ++ indio_dev->num_channels = channels; + +- size = (indio_dev->num_channels + 1) * sizeof(struct iio_map); ++ size = (channels + 1) * sizeof(struct iio_map); + adc_dev->map = kzalloc(size, GFP_KERNEL); + if (adc_dev->map == NULL) { + kfree(chan_array); +@@ -203,7 +212,7 @@ static int __devinit tiadc_probe(struct platform_device *pdev) + + tiadc_step_config(adc_dev); + +- err = tiadc_channel_init(indio_dev, adc_dev->channels); ++ err = tiadc_channel_init(indio_dev, adc_dev); + if (err < 0) + goto err_free_device; + +@@ -213,6 +222,8 @@ static int __devinit tiadc_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, indio_dev); + ++ dev_info(&pdev->dev, "Initialized\n"); ++ + return 0; + + err_free_channels: +diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c +index 7a26810..d09e1a7 100644 +--- a/drivers/input/touchscreen/ti_am335x_tsc.c ++++ b/drivers/input/touchscreen/ti_am335x_tsc.c +@@ -26,6 +26,7 @@ + #include <linux/io.h> + #include <linux/input/ti_am335x_tsc.h> + #include <linux/delay.h> ++#include <linux/regmap.h> + + #include <linux/mfd/ti_am335x_tscadc.h> + +@@ -64,13 +65,17 @@ struct titsc { + + static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) + { +- return readl(ts->mfd_tscadc->tscadc_base + reg); ++ unsigned int val; ++ ++ val = (unsigned int)-1; ++ regmap_read(ts->mfd_tscadc->regmap_tscadc, reg, &val); ++ return val; + } + + static void titsc_writel(struct titsc *tsc, unsigned int reg, + unsigned int val) + { +- writel(val, tsc->mfd_tscadc->tscadc_base + reg); ++ regmap_write(tsc->mfd_tscadc->regmap_tscadc, reg, val); + } + + /* +@@ -455,10 +460,15 @@ static int __devinit titsc_probe(struct platform_device *pdev) + + /* register to the input system */ + err = input_register_device(input_dev); +- if (err) ++ if (err) { ++ dev_err(&pdev->dev, "Failed to register input device\n"); + goto err_free_irq; ++ } + + platform_set_drvdata(pdev, ts_dev); ++ ++ dev_info(&pdev->dev, "Initialized OK\n"); ++ + return 0; + + err_free_irq: +diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c +index cbb8b70c..4a7041c 100644 +--- a/drivers/mfd/ti_am335x_tscadc.c ++++ b/drivers/mfd/ti_am335x_tscadc.c +@@ -31,6 +31,7 @@ static unsigned int tscadc_readl(struct ti_tscadc_dev *tsadc, unsigned int reg) + { + unsigned int val; + ++ val = (unsigned int)-1; + regmap_read(tsadc->regmap_tscadc, reg, &val); + return val; + } +@@ -68,7 +69,7 @@ static int __devinit ti_tscadc_probe(struct platform_device *pdev) + int irq; + int err, ctrl; + int clk_value, clock_rate; +- int tsc_wires, adc_channels = 0, total_channels; ++ int tsc_wires = 0, adc_channels = 0, total_channels; + + if (!pdata) { + dev_err(&pdev->dev, "Could not find platform data\n"); +@@ -78,7 +79,9 @@ static int __devinit ti_tscadc_probe(struct platform_device *pdev) + if (pdata->adc_init) + adc_channels = pdata->adc_init->adc_channels; + +- tsc_wires = pdata->tsc_init->wires; ++ if (pdata->tsc_init) ++ tsc_wires = pdata->tsc_init->wires; ++ + total_channels = tsc_wires + adc_channels; + + if (total_channels > 8) { diff --git a/patches/linux-3.7-rc6/0059-ARM-OMAP3-hwmod-Corrects-resource-data-for-PWM-devic.patch b/patches/linux-3.7-rc6/0059-ARM-OMAP3-hwmod-Corrects-resource-data-for-PWM-devic.patch new file mode 100644 index 0000000..a50a7c1 --- /dev/null +++ b/patches/linux-3.7-rc6/0059-ARM-OMAP3-hwmod-Corrects-resource-data-for-PWM-devic.patch @@ -0,0 +1,165 @@ +From ef11a2c0cc3cc0c1b8ea1d96a4ead994b0175f02 Mon Sep 17 00:00:00 2001 +From: "Philip, Avinash" <avinashphilip@ti.com> +Date: Mon, 2 Jul 2012 13:51:39 +0530 +Subject: [PATCH] ARM: OMAP3+: hwmod: Corrects resource data for PWM devices. + +PWM device has common space + module specific part in AM335x. To access +module specific part from module drivers, resource regions for PWM +device rearranged to access module specific part with index 0. This +helps module re-usability for platforms that didn't have config space +support like Davinci. Also ADDR_TYPE_RT flag removed for module specific +part. + +Signed-off-by: Philip, Avinash <avinashphilip@ti.com> +--- + arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 72 ++++++++++++++-------------- + 1 file changed, 36 insertions(+), 36 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +index f96bbc0..b6f78c1 100644 +--- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c ++++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +@@ -2549,17 +2549,17 @@ static struct omap_hwmod_ocp_if am33xx_l4_ls__elm = { + + /* + * Splitting the resources to handle access of PWMSS config space +- * and module specific part independently ++ * and module specific part independently. Also resources being ++ * arranged to be compatible with driver + */ + static struct omap_hwmod_addr_space am33xx_ehrpwm0_addr_space[] = { + { +- .pa_start = 0x48300000, +- .pa_end = 0x48300000 + SZ_16 - 1, +- .flags = ADDR_TYPE_RT +- }, +- { + .pa_start = 0x48300200, + .pa_end = 0x48300200 + SZ_256 - 1, ++ }, ++ { ++ .pa_start = 0x48300000, ++ .pa_end = 0x48300000 + SZ_16 - 1, + .flags = ADDR_TYPE_RT + }, + { } +@@ -2575,17 +2575,17 @@ static struct omap_hwmod_ocp_if am33xx_l4_ls__ehrpwm0 = { + + /* + * Splitting the resources to handle access of PWMSS config space +- * and module specific part independently ++ * and module specific part independently. Also resources being ++ * arranged to be compatible with driver + */ + static struct omap_hwmod_addr_space am33xx_ehrpwm1_addr_space[] = { + { +- .pa_start = 0x48302000, +- .pa_end = 0x48302000 + SZ_16 - 1, +- .flags = ADDR_TYPE_RT +- }, +- { + .pa_start = 0x48302200, + .pa_end = 0x48302200 + SZ_256 - 1, ++ }, ++ { ++ .pa_start = 0x48302000, ++ .pa_end = 0x48302000 + SZ_16 - 1, + .flags = ADDR_TYPE_RT + }, + { } +@@ -2601,17 +2601,17 @@ static struct omap_hwmod_ocp_if am33xx_l4_ls__ehrpwm1 = { + + /* + * Splitting the resources to handle access of PWMSS config space +- * and module specific part independently ++ * and module specific part independently. Also resources being ++ * arranged to be compatible with driver + */ + static struct omap_hwmod_addr_space am33xx_ehrpwm2_addr_space[] = { + { +- .pa_start = 0x48304000, +- .pa_end = 0x48304000 + SZ_16 - 1, +- .flags = ADDR_TYPE_RT +- }, +- { + .pa_start = 0x48304200, + .pa_end = 0x48304200 + SZ_256 - 1, ++ }, ++ { ++ .pa_start = 0x48304000, ++ .pa_end = 0x48304000 + SZ_16 - 1, + .flags = ADDR_TYPE_RT + }, + { } +@@ -2627,17 +2627,17 @@ static struct omap_hwmod_ocp_if am33xx_l4_ls__ehrpwm2 = { + + /* + * Splitting the resources to handle access of PWMSS config space +- * and module specific part independently ++ * and module specific part independently. Also resources being ++ * arranged to be compatible with driver + */ + static struct omap_hwmod_addr_space am33xx_ecap0_addr_space[] = { + { +- .pa_start = 0x48300000, +- .pa_end = 0x48300000 + SZ_16 - 1, +- .flags = ADDR_TYPE_RT +- }, +- { + .pa_start = 0x48300100, + .pa_end = 0x48300100 + SZ_256 - 1, ++ }, ++ { ++ .pa_start = 0x48300000, ++ .pa_end = 0x48300000 + SZ_16 - 1, + .flags = ADDR_TYPE_RT + }, + { } +@@ -2653,17 +2653,17 @@ static struct omap_hwmod_ocp_if am33xx_l4_ls__ecap0 = { + + /* + * Splitting the resources to handle access of PWMSS config space +- * and module specific part independently ++ * and module specific part independently. Also resources being ++ * arranged to be compatible with driver + */ + static struct omap_hwmod_addr_space am33xx_ecap1_addr_space[] = { + { +- .pa_start = 0x48302000, +- .pa_end = 0x48302000 + SZ_16 - 1, +- .flags = ADDR_TYPE_RT +- }, +- { + .pa_start = 0x48302100, + .pa_end = 0x48302100 + SZ_256 - 1, ++ }, ++ { ++ .pa_start = 0x48302000, ++ .pa_end = 0x48302000 + SZ_16 - 1, + .flags = ADDR_TYPE_RT + }, + { } +@@ -2679,17 +2679,17 @@ static struct omap_hwmod_ocp_if am33xx_l4_ls__ecap1 = { + + /* + * Splitting the resources to handle access of PWMSS config space +- * and module specific part independently ++ * and module specific part independently. Also resources being ++ * arranged to be compatible with driver + */ + static struct omap_hwmod_addr_space am33xx_ecap2_addr_space[] = { + { +- .pa_start = 0x48304000, +- .pa_end = 0x48304000 + SZ_16 - 1, +- .flags = ADDR_TYPE_RT +- }, +- { + .pa_start = 0x48304100, + .pa_end = 0x48304100 + SZ_256 - 1, ++ }, ++ { ++ .pa_start = 0x48304000, ++ .pa_end = 0x48304000 + SZ_16 - 1, + .flags = ADDR_TYPE_RT + }, + { } diff --git a/patches/linux-3.7-rc6/0060-pwm_backlight-Add-device-tree-support-for-Low-Thresh.patch b/patches/linux-3.7-rc6/0060-pwm_backlight-Add-device-tree-support-for-Low-Thresh.patch new file mode 100644 index 0000000..4a6d3c3 --- /dev/null +++ b/patches/linux-3.7-rc6/0060-pwm_backlight-Add-device-tree-support-for-Low-Thresh.patch @@ -0,0 +1,68 @@ +From 9deb78bb727ab7c632f240dc57af845f39e618c8 Mon Sep 17 00:00:00 2001 +From: "Philip, Avinash" <avinashphilip@ti.com> +Date: Mon, 16 Jul 2012 14:59:41 +0530 +Subject: [PATCH] pwm_backlight: Add device tree support for Low Threshold + Brightness + +Low Threshold Brightness should be configured to have a linear relation +in brightness scale. This patch adds device tree support for low +threshold brightness as optional one for pwm_backlight. + +Signed-off-by: Philip, Avinash <avinashphilip@ti.com> +--- + .../bindings/video/backlight/pwm-backlight.txt | 21 ++++++++++++++++++++ + drivers/video/backlight/pwm_bl.c | 5 +++++ + 2 files changed, 26 insertions(+) + +diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt +index 1e4fc72..689c7d2 100644 +--- a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt ++++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt +@@ -14,6 +14,8 @@ Required properties: + Optional properties: + - pwm-names: a list of names for the PWM devices specified in the + "pwms" property (see PWM binding[0]) ++ - low_threshold_brightness: brightness threshold low level. (get linear ++ scales in brightness in low end of brightness levels) + + [0]: Documentation/devicetree/bindings/pwm/pwm.txt + +@@ -26,3 +28,22 @@ Example: + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + }; ++ ++Example for brightness_threshold_level: ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm 0 50000>; ++ ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <6>; ++ low_threshold_brightness = <50>; ++ }; ++}; ++Note: ++Low threshold support is required to have linear brightness scale from ++0 to max. For some panels, backlight absent on low end of brightness ++scale. So support for Low Threshold been required. So that the scale of ++brightness changed from Low Threshold to Max in scales defined in ++brightness-levels. In this example 20% maximum brightness scale should ++be required to turn on panel backlight. +diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c +index 069983c..0c91023 100644 +--- a/drivers/video/backlight/pwm_bl.c ++++ b/drivers/video/backlight/pwm_bl.c +@@ -143,6 +143,11 @@ static int pwm_backlight_parse_dt(struct device *dev, + + data->dft_brightness = value; + data->max_brightness--; ++ ++ ret = of_property_read_u32(node, "low_threshold_brightness", ++ &value); ++ if (!ret) ++ data->lth_brightness = value; + } + + /* diff --git a/patches/linux-3.7-rc6/0061-pwm-pwm-tiecap-Add-device-tree-binding-support-in-AP.patch b/patches/linux-3.7-rc6/0061-pwm-pwm-tiecap-Add-device-tree-binding-support-in-AP.patch new file mode 100644 index 0000000..1bf1097 --- /dev/null +++ b/patches/linux-3.7-rc6/0061-pwm-pwm-tiecap-Add-device-tree-binding-support-in-AP.patch @@ -0,0 +1,120 @@ +From 6a9abd983cbbd369707b4b7edc3b9b45aa80a4b1 Mon Sep 17 00:00:00 2001 +From: "Philip, Avinash" <avinashphilip@ti.com> +Date: Fri, 29 Jun 2012 10:52:57 +0530 +Subject: [PATCH] pwm: pwm-tiecap: Add device-tree binding support in APWM + driver + +Adds support for device-tree binding in ECAP APWM driver and custom +of_xlate support. In custom of_xlate support, support for configuring +polarity also been provided. This will provide configuration of ECAP +APWM polarity from client drivers device-tree. +Also size of pwm-cells set to 3 to support polarity configuration from +device tree. + +Signed-off-by: Philip, Avinash <avinashphilip@ti.com> +--- + Documentation/devicetree/bindings/pwm/ecap-pwm.txt | 24 ++++++++++++++ + drivers/pwm/pwm-tiecap.c | 35 ++++++++++++++++++++ + 2 files changed, 59 insertions(+) + create mode 100644 Documentation/devicetree/bindings/pwm/ecap-pwm.txt + +diff --git a/Documentation/devicetree/bindings/pwm/ecap-pwm.txt b/Documentation/devicetree/bindings/pwm/ecap-pwm.txt +new file mode 100644 +index 0000000..fa56534 +--- /dev/null ++++ b/Documentation/devicetree/bindings/pwm/ecap-pwm.txt +@@ -0,0 +1,24 @@ ++TI SOC ECAP based APWM controller ++ ++Required properties: ++- compatible : Must be "ti, ecap" ++- ti,hwmods : Must be "ecap<n>", n being the instance number (0-based) ++- #pwm-cells: On ECAP the number of cells used to specify a PWM is 3. The ++ first cell specifies the per-chip index of the PWM to use, the second ++ cell is the period cycle in nanoseconds and the third cell is the ++ polarity of PWM output. Polarity 0 gives normal polarity and 1 gives ++ inversed polarity (inverse duty cycle) ++ ++Note: Current implementation will fetch base address, irq and dma ++from omap hwmod data base during device registration. ++Future plan is to migrate hwmod data base contents into device tree ++blob so that, all the required data will be used from device tree dts ++file. ++ ++Example: ++ ++ ecap0: ecap@0 { ++ compatible = "ti, ecap"; ++ ti,hwmods = "ecap0"; ++ #pwm-cells = <3>; ++ }; +diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c +index d6d4cf0..d15941c 100644 +--- a/drivers/pwm/pwm-tiecap.c ++++ b/drivers/pwm/pwm-tiecap.c +@@ -37,6 +37,8 @@ + #define ECCTL2_SYNC_SEL_DISA (BIT(7) | BIT(6)) + #define ECCTL2_TSCTR_FREERUN BIT(4) + ++#define PWM_CELL_SIZE 3 ++ + struct ecap_pwm_chip { + struct pwm_chip chip; + unsigned int clk_rate; +@@ -184,6 +186,26 @@ static const struct pwm_ops ecap_pwm_ops = { + .owner = THIS_MODULE, + }; + ++static struct pwm_device *of_ecap_xlate(struct pwm_chip *chip, ++ const struct of_phandle_args *args) ++{ ++ struct pwm_device *pwm; ++ ++ if (chip->of_pwm_n_cells < PWM_CELL_SIZE) ++ return ERR_PTR(-EINVAL); ++ ++ if (args->args[0] >= chip->npwm) ++ return ERR_PTR(-EINVAL); ++ ++ pwm = pwm_request_from_chip(chip, args->args[0], NULL); ++ if (IS_ERR(pwm)) ++ return pwm; ++ ++ pwm_set_period(pwm, args->args[1]); ++ pwm_set_polarity(pwm, args->args[2]); ++ return pwm; ++} ++ + static int __devinit ecap_pwm_probe(struct platform_device *pdev) + { + int ret; +@@ -211,6 +233,8 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev) + + pc->chip.dev = &pdev->dev; + pc->chip.ops = &ecap_pwm_ops; ++ pc->chip.of_xlate = of_ecap_xlate; ++ pc->chip.of_pwm_n_cells = PWM_CELL_SIZE; + pc->chip.base = -1; + pc->chip.npwm = 1; + +@@ -244,9 +268,20 @@ static int __devexit ecap_pwm_remove(struct platform_device *pdev) + return pwmchip_remove(&pc->chip); + } + ++#if defined(CONFIG_OF) ++static const struct of_device_id omap_ecap_of_match[] = { ++ { .compatible = "ti,ecap" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, omap_ecap_of_match); ++#endif ++ + static struct platform_driver ecap_pwm_driver = { + .driver = { + .name = "ecap", ++#if defined(CONFIG_OF) ++ .of_match_table = of_match_ptr(omap_ecap_of_match), ++#endif + }, + .probe = ecap_pwm_probe, + .remove = __devexit_p(ecap_pwm_remove), diff --git a/patches/linux-3.7-rc6/0062-Control-module-EHRPWM-clk-enabling.patch b/patches/linux-3.7-rc6/0062-Control-module-EHRPWM-clk-enabling.patch new file mode 100644 index 0000000..6ea83fe --- /dev/null +++ b/patches/linux-3.7-rc6/0062-Control-module-EHRPWM-clk-enabling.patch @@ -0,0 +1,43 @@ +From 6f3f226f97712e86991a805aa5e05e8734aa9f21 Mon Sep 17 00:00:00 2001 +From: "Philip, Avinash" <avinashphilip@ti.com> +Date: Tue, 22 May 2012 11:34:58 +0530 +Subject: [PATCH] Control module : EHRPWM clk enabling + +Signed-off-by: Philip, Avinash <avinashphilip@ti.com> +--- + arch/arm/mach-omap2/devices.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c +index c72b5a7..9faecb9 100644 +--- a/arch/arm/mach-omap2/devices.c ++++ b/arch/arm/mach-omap2/devices.c +@@ -434,6 +434,20 @@ static void omap_init_mcspi(void) + static inline void omap_init_mcspi(void) {} + #endif + ++#include "cm33xx.h" ++ ++int __init am33xx_register_ehrpwm(void) ++{ ++ void __iomem *iobase; ++ unsigned short regword; ++ ++ iobase = AM33XX_CM_REGADDR(0, 0x10664); ++ regword = readw(iobase); ++ regword |= 0x7; ++ writew(regword, iobase); ++ return 0; ++} ++ + /** + * omap_init_rng - bind the RNG hwmod to the RNG omap_device + * +@@ -720,6 +734,7 @@ static int __init omap2_init_devices(void) + omap_init_vout(); + omap_init_ocp2scp(); + ++ am33xx_register_ehrpwm(); + return 0; + } + arch_initcall(omap2_init_devices); diff --git a/patches/linux-3.7-rc6/0063-pwm-pwm-tiecap-Enable-clock-gating.patch b/patches/linux-3.7-rc6/0063-pwm-pwm-tiecap-Enable-clock-gating.patch new file mode 100644 index 0000000..8adb2c9 --- /dev/null +++ b/patches/linux-3.7-rc6/0063-pwm-pwm-tiecap-Enable-clock-gating.patch @@ -0,0 +1,102 @@ +From 33ed8e5aaf8a28e904bf0f3174cfc3a4cb3c5e50 Mon Sep 17 00:00:00 2001 +From: "Philip, Avinash" <avinashphilip@ti.com> +Date: Tue, 24 Jul 2012 14:58:09 +0530 +Subject: [PATCH] pwm: pwm-tiecap: Enable clock gating + +In AM335x SOC, clock to PWM modules is gated in common config space. +This commit adds support for enabling clock gating in the driver and +leave it enabled if config space node is present. + +Signed-off-by: Philip, Avinash <avinashphilip@ti.com> +--- + Documentation/devicetree/bindings/pwm/ecap-pwm.txt | 12 +++++++ + drivers/pwm/pwm-tiecap.c | 37 +++++++++++++++++++- + 2 files changed, 48 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/pwm/ecap-pwm.txt b/Documentation/devicetree/bindings/pwm/ecap-pwm.txt +index fa56534..7d83587 100644 +--- a/Documentation/devicetree/bindings/pwm/ecap-pwm.txt ++++ b/Documentation/devicetree/bindings/pwm/ecap-pwm.txt +@@ -9,6 +9,11 @@ Required properties: + polarity of PWM output. Polarity 0 gives normal polarity and 1 gives + inversed polarity (inverse duty cycle) + ++Optional properties: ++- has_configspace: Some ECAP hardwares has config space memory region ++ to enable clock gating to individual modules. Adding this as optional ++ properties. ++ + Note: Current implementation will fetch base address, irq and dma + from omap hwmod data base during device registration. + Future plan is to migrate hwmod data base contents into device tree +@@ -22,3 +27,10 @@ Example: + ti,hwmods = "ecap0"; + #pwm-cells = <3>; + }; ++Example with has_configspace: ++ ecap0: ecap@0 { ++ compatible = "ti, ecap"; ++ ti,hwmods = "ecap0"; ++ #pwm-cells = <3>; ++ has_configspace = <1>; ++ }; +diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c +index d15941c..5b07707 100644 +--- a/drivers/pwm/pwm-tiecap.c ++++ b/drivers/pwm/pwm-tiecap.c +@@ -206,12 +206,16 @@ static struct pwm_device *of_ecap_xlate(struct pwm_chip *chip, + return pwm; + } + ++#define CLKCONFIG 8 ++#define ECAP_CLK_EN 1 + static int __devinit ecap_pwm_probe(struct platform_device *pdev) + { +- int ret; ++ int ret, len; + struct resource *r; + struct clk *clk; + struct ecap_pwm_chip *pc; ++ void __iomem *mmio_base; ++ unsigned long regval; + + pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); + if (!pc) { +@@ -255,6 +259,37 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev) + } + + pm_runtime_enable(&pdev->dev); ++ ++ /* ++ * Some IP's have config space and require special handling of ++ * clock gating from config space. So enabling clock gating ++ * at config space. ++ */ ++ if (pdev->dev.of_node && of_find_property(pdev->dev.of_node, ++ "has_configspace", &len)) { ++ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!r) { ++ pm_runtime_disable(&pdev->dev); ++ dev_err(&pdev->dev, "no memory resource defined\n"); ++ return -ENODEV; ++ } ++ ++ mmio_base = devm_ioremap(&pdev->dev, r->start, ++ resource_size(r)); ++ if (!mmio_base) { ++ pm_runtime_disable(&pdev->dev); ++ dev_err(&pdev->dev, "failed to ioremap() registers\n"); ++ return -EADDRNOTAVAIL; ++ } ++ ++ pm_runtime_get_sync(&pdev->dev); ++ regval = readw(mmio_base + CLKCONFIG); ++ regval |= ECAP_CLK_EN; ++ writew(regval, mmio_base + CLKCONFIG); ++ pm_runtime_put_sync(&pdev->dev); ++ } ++ + platform_set_drvdata(pdev, pc); + return 0; + } diff --git a/patches/linux-3.7-rc6/0064-PWM-ti-ehrpwm-fix-up-merge-conflict.patch b/patches/linux-3.7-rc6/0064-PWM-ti-ehrpwm-fix-up-merge-conflict.patch new file mode 100644 index 0000000..c036093 --- /dev/null +++ b/patches/linux-3.7-rc6/0064-PWM-ti-ehrpwm-fix-up-merge-conflict.patch @@ -0,0 +1,22 @@ +From f650c07353651edeb2f3b56fc5628ca48e60609d Mon Sep 17 00:00:00 2001 +From: Koen Kooi <koen@dominion.thruhere.net> +Date: Mon, 17 Sep 2012 10:34:22 +0200 +Subject: [PATCH] PWM: ti-ehrpwm: fix up merge conflict + +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + drivers/pwm/pwm-tiehrpwm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c +index d3c1dff..288f93e 100644 +--- a/drivers/pwm/pwm-tiehrpwm.c ++++ b/drivers/pwm/pwm-tiehrpwm.c +@@ -113,6 +113,7 @@ struct ehrpwm_pwm_chip { + struct pwm_chip chip; + unsigned int clk_rate; + void __iomem *mmio_base; ++ unsigned long duty_cycles; + unsigned long period_cycles[NUM_PWM_CHANNEL]; + enum pwm_polarity polarity[NUM_PWM_CHANNEL]; + }; diff --git a/patches/linux-3.7-rc6/0065-pwm-pwm_test-Driver-support-for-PWM-module-testing.patch b/patches/linux-3.7-rc6/0065-pwm-pwm_test-Driver-support-for-PWM-module-testing.patch new file mode 100644 index 0000000..1036f6d --- /dev/null +++ b/patches/linux-3.7-rc6/0065-pwm-pwm_test-Driver-support-for-PWM-module-testing.patch @@ -0,0 +1,370 @@ +From a1655d02663d4cef923a9a75c60fb34f2e35c783 Mon Sep 17 00:00:00 2001 +From: "Philip, Avinash" <avinashphilip@ti.com> +Date: Tue, 17 Jul 2012 21:35:11 +0530 +Subject: [PATCH] pwm: pwm_test: Driver support for PWM module testing + +Signed-off-by: Philip, Avinash <avinashphilip@ti.com> +--- + drivers/pwm/Kconfig | 11 ++ + drivers/pwm/Makefile | 1 + + drivers/pwm/pwm_test.c | 322 ++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 334 insertions(+) + create mode 100644 drivers/pwm/pwm_test.c + +diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig +index ed81720..f1a0721 100644 +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -160,4 +160,15 @@ config PWM_VT8500 + To compile this driver as a module, choose M here: the module + will be called pwm-vt8500. + ++config EHRPWM_TEST ++ tristate "EHRPWM TEST support" ++ depends on PWM_TIEHRPWM ++ ++ help ++ Test driver support for the EHRPWM PWM driver found on AM33XX ++ TI SOC ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm_ehrpwm. ++ + endif +diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile +index acfe482..e2c6277 100644 +--- a/drivers/pwm/Makefile ++++ b/drivers/pwm/Makefile +@@ -13,3 +13,4 @@ obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o + obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o + obj-$(CONFIG_PWM_TWL6030) += pwm-twl6030.o + obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o ++obj-$(CONFIG_EHRPWM_TEST) += pwm_test.o +diff --git a/drivers/pwm/pwm_test.c b/drivers/pwm/pwm_test.c +new file mode 100644 +index 0000000..d9948db +--- /dev/null ++++ b/drivers/pwm/pwm_test.c +@@ -0,0 +1,322 @@ ++/* ++ * PWM Test driver ++ * ++ * Copyright (C) 2012 Texas Instruments. ++ * ++ * 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 <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/pwm.h> ++#include <linux/slab.h> ++#include <linux/io.h> ++#include <linux/err.h> ++#include <linux/clk.h> ++#include <linux/pm_runtime.h> ++ ++struct pwm_test { ++ struct pwm_device *pwm; ++ int ret; ++ struct class *pwm_test_class; ++ unsigned long period, duty, run, polarity, config, requested; ++ unsigned long period_s, duty_s, run_s, polarity_s, config_s, requested_s; ++ struct device *dev; ++}; ++ ++static ssize_t pwm_test_show_duty(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct pwm_test *pwm_test = dev_get_drvdata(dev); ++ return sprintf(buf, "%lu\n", pwm_test->duty); ++} ++ ++static ssize_t pwm_test_store_duty(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int rc; ++ struct pwm_test *pwm_test = dev_get_drvdata(dev); ++ ++ rc = kstrtoul(buf, 0, &pwm_test->duty_s); ++ if (rc) ++ return rc; ++ return count; ++} ++ ++static ssize_t pwm_test_show_period(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct pwm_test *pwm_test = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%lu\n", pwm_test->period); ++} ++ ++static ssize_t pwm_test_store_period(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int rc; ++ struct pwm_test *pwm_test = dev_get_drvdata(dev); ++ ++ rc = kstrtoul(buf, 0, &pwm_test->period_s); ++ if (rc) ++ return rc; ++ ++ return count; ++} ++ ++static ssize_t pwm_test_show_config(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct pwm_test *pwm_test = dev_get_drvdata(dev); ++ if (pwm_test->config) ++ return sprintf(buf, "config Done\n"); ++ else ++ return sprintf(buf, "config Failed\n"); ++} ++static ssize_t pwm_test_store_config(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct pwm_test *pwm_test = dev_get_drvdata(dev); ++ int ret; ++ ++ if (pwm_test->duty_s == 0) { ++ ret = pwm_config(pwm_test->pwm, 0, pwm_test->period_s); ++ if (ret) { ++ pwm_test->config = 0; ++ pr_err("operation failed %d\n", ret); ++ pwm_test->duty_s = pwm_test->duty; ++ pwm_test->period_s = pwm_test->period; ++ return ret; ++ } ++ pwm_test->duty = pwm_test->duty_s; ++ pwm_test->period = pwm_test->period_s; ++ pwm_test->config = 1; ++ } else { ++ ret = pwm_config(pwm_test->pwm, pwm_test->duty_s, ++ pwm_test->period_s); ++ if (ret) { ++ pwm_test->config = 0; ++ pr_err("operation failed %d\n", ret); ++ pwm_test->duty_s = pwm_test->duty; ++ pwm_test->period_s = pwm_test->period; ++ return ret; ++ } ++ pwm_test->duty = pwm_test->duty_s; ++ pwm_test->period = pwm_test->period_s; ++ pwm_test->config = 1; ++ } ++ return count; ++} ++ ++static ssize_t pwm_test_show_run(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct pwm_test *pwm_test = dev_get_drvdata(dev); ++ return sprintf(buf, "%s\n", pwm_test->run ? "Enabled" : "Disabled"); ++} ++ ++static ssize_t pwm_test_store_run(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int rc; ++ struct pwm_test *pwm_test = dev_get_drvdata(dev); ++ ++ rc = kstrtoul(buf, 0, &pwm_test->run_s); ++ if (rc) ++ return rc; ++ ++ if (pwm_test->run_s) ++ rc = pwm_enable(pwm_test->pwm); ++ else ++ pwm_disable(pwm_test->pwm); ++ ++ if (rc) { ++ pr_err("operation failed %d\n", rc); ++ pwm_test->run_s = pwm_test->run; ++ return rc; ++ } ++ ++ pwm_test->run = pwm_test->run_s; ++ return count; ++} ++ ++static ssize_t pwm_test_show_polarity(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct pwm_test *pwm_test = dev_get_drvdata(dev); ++ return sprintf(buf, "%s\n", ++ pwm_test->polarity ? "Polarity Inversed" : ++ "Polarity Normal"); ++} ++ ++static ssize_t pwm_test_store_polarity(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int rc; ++ struct pwm_test *pwm_test = dev_get_drvdata(dev); ++ ++ rc = kstrtoul(buf, 0, &pwm_test->polarity_s); ++ if (rc) ++ return rc; ++ ++ rc = pwm_set_polarity(pwm_test->pwm, pwm_test->polarity_s); ++ if (rc) { ++ pr_err("operation failed %d\n", rc); ++ return rc; ++ } ++ ++ pwm_test->polarity = pwm_test->polarity_s; ++ return count; ++} ++ ++static ssize_t pwm_test_show_request(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct pwm_test *pwm_test = dev_get_drvdata(dev); ++ return sprintf(buf, "%s\n", pwm_test->requested ? "Requested" : "Freed"); ++} ++ ++static ssize_t pwm_test_store_request(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int rc; ++ struct pwm_test *pwm_test = dev_get_drvdata(dev); ++ ++ rc = kstrtoul(buf, 0, &pwm_test->requested_s); ++ if (rc) ++ return rc; ++ ++ if (pwm_test->requested_s) { ++ pwm_test->pwm = pwm_get(dev, NULL); ++ ++ if (IS_ERR(pwm_test->pwm)) { ++ dev_err(dev, "%s() %d %ld\n", __func__, __LINE__, ++ PTR_ERR(pwm_test->pwm)); ++ rc = -EINVAL; ++ } ++ } else { ++ pwm_free(pwm_test->pwm); ++ pwm_test->polarity = 0; ++ pwm_test->run = 0; ++ pwm_test->duty = 0; ++ pwm_test->period = 0; ++ pwm_test->config = 0; ++ pwm_test->polarity_s = 0; ++ pwm_test->run_s = 0; ++ pwm_test->duty_s = 0; ++ pwm_test->period_s = 0; ++ pwm_test->config_s = 0; ++ rc = 0; ++ } ++ ++ if (rc) { ++ pr_err("operation failed %d\n", rc); ++ pwm_test->requested_s = pwm_test->requested; ++ return rc; ++ } ++ ++ pwm_test->requested = pwm_test->requested_s; ++ return count; ++} ++ ++static DEVICE_ATTR(duty, 0644, pwm_test_show_duty, pwm_test_store_duty); ++static DEVICE_ATTR(period, 0644, pwm_test_show_period, pwm_test_store_period); ++static DEVICE_ATTR(polarity, 0644, pwm_test_show_polarity, ++ pwm_test_store_polarity); ++static DEVICE_ATTR(config, 0644 , pwm_test_show_config, pwm_test_store_config); ++static DEVICE_ATTR(run, 0644 , pwm_test_show_run, pwm_test_store_run); ++static DEVICE_ATTR(request, 0644 , pwm_test_show_request, pwm_test_store_request); ++ ++static const struct attribute *pwm_attrs[] = { ++ &dev_attr_duty.attr, ++ &dev_attr_period.attr, ++ &dev_attr_config.attr, ++ &dev_attr_run.attr, ++ &dev_attr_request.attr, ++ &dev_attr_polarity.attr, ++ NULL, ++}; ++ ++static const struct attribute_group pwm_device_attr_group = { ++ .attrs = (struct attribute **) pwm_attrs, ++}; ++ ++static int __init pwm_test_class_init(struct device *dev) ++{ ++ if (sysfs_create_group(&dev->kobj, &pwm_device_attr_group)) ++ return 1; ++ return 0; ++} ++ ++static int pwm_test_probe(struct platform_device *pdev) ++{ ++ struct pwm_test *pwm_test; ++ ++ pwm_test = devm_kzalloc(&pdev->dev, sizeof(*pwm_test), GFP_KERNEL); ++ ++ if (!pwm_test) { ++ dev_err(&pdev->dev, "memory error\n"); ++ return -ENOMEM; ++ } ++ ++ if (pwm_test_class_init(&pdev->dev)) { ++ dev_err(&pdev->dev, "sysfs creation failed\n"); ++ return -EINVAL; ++ } ++ dev_set_drvdata(&pdev->dev, pwm_test); ++ platform_set_drvdata(pdev, pwm_test); ++ return 0; ++} ++ ++static int pwm_test_remove(struct platform_device *pdev) ++{ ++ struct pwm_test *pwm_test = platform_get_drvdata(pdev); ++ ++ if (!pwm_test->ret) { ++ pwm_config(pwm_test->pwm, 0, 0x1000); ++ pwm_disable(pwm_test->pwm); ++ pr_emerg("PWM Device Disabled %s\n", dev_name(&pdev->dev)); ++ } ++ if (pwm_test->requested) ++ pwm_free(pwm_test->pwm); ++ ++ pr_emerg("PWM Device Freed %s\n", dev_name(&pdev->dev)); ++ pwm_test->run = 0; ++ sysfs_remove_group(&pdev->dev.kobj, &pwm_device_attr_group); ++ return 0; ++} ++ ++static struct of_device_id pwm_test_of_match[] = { ++ { .compatible = "pwm_test" }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(of, pwm_test_of_match); ++ ++static struct platform_driver pwm_test_driver = { ++ .driver = { ++ .name = "pwm_test", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(pwm_test_of_match), ++ }, ++ .probe = pwm_test_probe, ++ .remove = pwm_test_remove, ++}; ++ ++module_platform_driver(pwm_test_driver); ++ ++MODULE_DESCRIPTION("pwm_test Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:pwm_test"); diff --git a/patches/linux-3.7-rc6/0066-arm-dts-DT-support-for-EHRPWM-and-ECAP-device.patch b/patches/linux-3.7-rc6/0066-arm-dts-DT-support-for-EHRPWM-and-ECAP-device.patch new file mode 100644 index 0000000..a4ff6bd --- /dev/null +++ b/patches/linux-3.7-rc6/0066-arm-dts-DT-support-for-EHRPWM-and-ECAP-device.patch @@ -0,0 +1,84 @@ +From 335aa3e5347097e0ef7ba046e59d9bb9cffa8a48 Mon Sep 17 00:00:00 2001 +From: "Philip, Avinash" <avinashphilip@ti.com> +Date: Wed, 11 Jul 2012 11:01:33 +0530 +Subject: [PATCH] arm/dts: DT support for EHRPWM and ECAP device. + +Adds DT support for EHRPWM and ECAP APWM device. Also sets size of +pwm-cells to 3 to support - <PWM instance number>, <PWM period> in +nano-seconds and <PWM polarity>. + +Signed-off-by: Philip, Avinash <avinashphilip@ti.com> +--- + arch/arm/boot/dts/am33xx.dtsi | 60 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 60 insertions(+) + +diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi +index 9755276..433065e 100644 +--- a/arch/arm/boot/dts/am33xx.dtsi ++++ b/arch/arm/boot/dts/am33xx.dtsi +@@ -376,5 +376,65 @@ + }; + + }; ++ ++ ehrpwm0: ehrpwm@48300200 { ++ compatible = "ti,omap2-ehrpwm"; ++ reg = <0x48300200 0x100 0x48300000 0x10>; ++ interrupt-parent = <&intc>; ++ interrupt = <86 58>; ++ ti,hwmods = "ehrpwm0"; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ ehrpwm1: ehrpwm@48302200 { ++ compatible = "ti,omap2-ehrpwm"; ++ reg = <0x48302200 0x100 0x48302000 0x10>; ++ interrupt-parent = <&intc>; ++ interrupt = <87 59>; ++ ti,hwmods = "ehrpwm1"; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ ehrpwm2: ehrpwm@48304200 { ++ compatible = "ti,omap2-ehrpwm"; ++ reg = <0x48304200 0x100 0x48304000 0x10>; ++ interrupt-parent = <&intc>; ++ interrupt = <39 60>; ++ ti,hwmods = "ehrpwm2"; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ ecap0: ecap@48300100 { ++ compatible = "ti,omap2-ecap"; ++ reg = <0x48300100 0x80 0x48300000 0x10>; ++ interrupt-parent = <&intc>; ++ interrupt = <31>; ++ ti,hwmods = "ecap0"; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ ecap1: ecap@48302100 { ++ compatible = "ti,omap2-ecap"; ++ reg = <0x48302100 0x80 0x48302000 0x10>; ++ interrupt-parent = <&intc>; ++ interrupt = <47>; ++ ti,hwmods = "ecap1"; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ ecap2: ecap@48304100 { ++ compatible = "ti,omap2-ecap"; ++ reg = <0x48304100 0x80 0x48304000 0x10>; ++ interrupt-parent = <&intc>; ++ interrupt = <61>; ++ ti,hwmods = "ecap2"; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; + }; + }; diff --git a/patches/linux-3.7-rc6/0067-pwm-pwm-tiehrpwm-Add-device-tree-binding-support-EHR.patch b/patches/linux-3.7-rc6/0067-pwm-pwm-tiehrpwm-Add-device-tree-binding-support-EHR.patch new file mode 100644 index 0000000..4da3741 --- /dev/null +++ b/patches/linux-3.7-rc6/0067-pwm-pwm-tiehrpwm-Add-device-tree-binding-support-EHR.patch @@ -0,0 +1,122 @@ +From 2d9a549a27aad6c8a87878c3620e1c0812af8da1 Mon Sep 17 00:00:00 2001 +From: "Philip, Avinash" <avinashphilip@ti.com> +Date: Mon, 2 Jul 2012 14:03:53 +0530 +Subject: [PATCH] pwm: pwm-tiehrpwm: Add device-tree binding support EHRPWM + driver + +Adds device-tree binding support in EHRWPM driver and custom of_xlate +support. In custom of_xlate support, support for configuring polarity +also been provided. This will provide configuration of EHRPWM polarity +from client drivers device-tree. +Also size of pwm-cells set to 3 to support polarity configuration from +device tree. + +Signed-off-by: Philip, Avinash <avinashphilip@ti.com> + +Conflicts: + drivers/pwm/pwm-tiehrpwm.c +--- + .../devicetree/bindings/pwm/ehrpwm-pwm.txt | 24 ++++++++++++++ + drivers/pwm/pwm-tiehrpwm.c | 34 ++++++++++++++++++++ + 2 files changed, 58 insertions(+) + create mode 100644 Documentation/devicetree/bindings/pwm/ehrpwm-pwm.txt + +diff --git a/Documentation/devicetree/bindings/pwm/ehrpwm-pwm.txt b/Documentation/devicetree/bindings/pwm/ehrpwm-pwm.txt +new file mode 100644 +index 0000000..a11543c +--- /dev/null ++++ b/Documentation/devicetree/bindings/pwm/ehrpwm-pwm.txt +@@ -0,0 +1,24 @@ ++TI SOC EHRPWM based PWM controller ++ ++Required properties: ++- compatible : Must be "ti, ehrpwm" ++- ti,hwmods : Must be "ehrpwm<n>", n being the instance number (0-based) ++- #pwm-cells: On EHRPWM the number of cells used to specify a PWM is 3. The ++ first cell specifies the per-chip index of the PWM to use, the second ++ cell is the period cycle in nanoseconds and the third cell is the ++ polarity of PWM output. Polarity 0 gives normal polarity and 1 gives ++ inversed polarity (inverse duty cycle) ++ ++Note: Current implementation will fetch base address, irq and dma ++from omap hwmod data base during device registration. ++Future plan is to migrate hwmod data base contents into device tree ++blob so that, all the required data will be used from device tree dts ++file. ++ ++Example: ++ ++ ehrpwm0: ehrpwm@0 { ++ compatible = "ti, ehrpwm"; ++ ti,hwmods = "ehrpwm0"; ++ #pwm-cells = <3>; ++ }; +diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c +index 288f93e..4f1e467 100644 +--- a/drivers/pwm/pwm-tiehrpwm.c ++++ b/drivers/pwm/pwm-tiehrpwm.c +@@ -108,6 +108,7 @@ + #define AQCSFRC_CSFA_DISSWFRC (BIT(1) | BIT(0)) + + #define NUM_PWM_CHANNEL 2 /* EHRPWM channels */ ++#define PWM_CELL_SIZE 3 + + struct ehrpwm_pwm_chip { + struct pwm_chip chip; +@@ -393,6 +394,26 @@ static const struct pwm_ops ehrpwm_pwm_ops = { + .owner = THIS_MODULE, + }; + ++static struct pwm_device *of_ehrpwm_xlate(struct pwm_chip *chip, ++ const struct of_phandle_args *args) ++{ ++ struct pwm_device *pwm; ++ ++ if (chip->of_pwm_n_cells < PWM_CELL_SIZE) ++ return ERR_PTR(-EINVAL); ++ ++ if (args->args[0] >= chip->npwm) ++ return ERR_PTR(-EINVAL); ++ ++ pwm = pwm_request_from_chip(chip, args->args[0], NULL); ++ if (IS_ERR(pwm)) ++ return pwm; ++ ++ pwm_set_period(pwm, args->args[1]); ++ pwm_set_polarity(pwm, args->args[2]); ++ return pwm; ++} ++ + static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev) + { + int ret; +@@ -420,6 +441,8 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev) + + pc->chip.dev = &pdev->dev; + pc->chip.ops = &ehrpwm_pwm_ops; ++ pc->chip.of_xlate = of_ehrpwm_xlate; ++ pc->chip.of_pwm_n_cells = PWM_CELL_SIZE; + pc->chip.base = -1; + pc->chip.npwm = NUM_PWM_CHANNEL; + +@@ -453,9 +476,20 @@ static int __devexit ehrpwm_pwm_remove(struct platform_device *pdev) + return pwmchip_remove(&pc->chip); + } + ++#if defined(CONFIG_OF) ++static const struct of_device_id omap_ehrpwm_of_match[] = { ++ { .compatible = "ti,omap2-ehrpwm" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, omap_ehrpwm_of_match); ++#endif ++ + static struct platform_driver ehrpwm_pwm_driver = { + .driver = { + .name = "ehrpwm", ++#if defined(CONFIG_OF) ++ .of_match_table = of_match_ptr(omap_ehrpwm_of_match), ++#endif + }, + .probe = ehrpwm_pwm_probe, + .remove = __devexit_p(ehrpwm_pwm_remove), diff --git a/patches/linux-3.7-rc6/0069-pinctrl-pinctrl-single-must-be-initialized-early.patch b/patches/linux-3.7-rc6/0069-pinctrl-pinctrl-single-must-be-initialized-early.patch new file mode 100644 index 0000000..0862d29 --- /dev/null +++ b/patches/linux-3.7-rc6/0069-pinctrl-pinctrl-single-must-be-initialized-early.patch @@ -0,0 +1,35 @@ +From 3a0f046cac46f4b1cc0a8e544dba30afcae91f3d Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Sat, 15 Sep 2012 12:00:41 +0300 +Subject: [PATCH] pinctrl: pinctrl-single must be initialized early. + +When using pinctrl-single to handle i2c initialization, it has +to be done early. Whether this is the best way to do so, is an +exercise left to the reader. +--- + drivers/pinctrl/pinctrl-single.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c +index 726a729..2b258c3 100644 +--- a/drivers/pinctrl/pinctrl-single.c ++++ b/drivers/pinctrl/pinctrl-single.c +@@ -1014,7 +1014,17 @@ static struct platform_driver pcs_driver = { + }, + }; + +-module_platform_driver(pcs_driver); ++static int __init pcs_init(void) ++{ ++ return platform_driver_register(&pcs_driver); ++} ++postcore_initcall(pcs_init); ++ ++static void __exit pcs_exit(void) ++{ ++ platform_driver_unregister(&pcs_driver); ++} ++module_exit(pcs_exit); + + MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); + MODULE_DESCRIPTION("One-register-per-pin type device tree based pinctrl driver"); diff --git a/patches/linux-3.7-rc6/0070-Bone-DTS-working-i2c2-i2c3-in-the-tree.patch b/patches/linux-3.7-rc6/0070-Bone-DTS-working-i2c2-i2c3-in-the-tree.patch new file mode 100644 index 0000000..4472434 --- /dev/null +++ b/patches/linux-3.7-rc6/0070-Bone-DTS-working-i2c2-i2c3-in-the-tree.patch @@ -0,0 +1,94 @@ +From cc8421dbb5b79561a93b29d4f29959f61471757e Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Sat, 15 Sep 2012 12:05:04 +0300 +Subject: [PATCH] Bone DTS working i2c2 (i2c3 in the tree) + +--- + arch/arm/boot/dts/am335x-bone.dts | 60 ++++++++++++++++++++++++++++++------- + 1 file changed, 50 insertions(+), 10 deletions(-) + +diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts +index 87686e9..d1c21ba 100644 +--- a/arch/arm/boot/dts/am335x-bone.dts ++++ b/arch/arm/boot/dts/am335x-bone.dts +@@ -52,6 +52,12 @@ + 0x60 0x17 /* gpmc_a8.gpio1_24, OUTPUT_PULLUP | MODE7 */ + >; + }; ++ i2c3_pins: pinmux_i2c3_pins { ++ pinctrl-single,pins = < ++ 0x178 0x73 /* uart1_ctsn.i2c2_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */ ++ 0x17c 0x73 /* uart1_rtsn.i2c2_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */ ++ >; ++ }; + }; + + ocp { +@@ -92,16 +98,6 @@ + }; + }; + +- i2c1: i2c@44e0b000 { +- status = "okay"; +- clock-frequency = <400000>; +- +- tps: tps@24 { +- reg = <0x24>; +- }; +- +- }; +- + gpevt { + compatible = "gpevt"; + pinctrl-names = "default"; +@@ -113,6 +109,50 @@ + }; + }; + ++&i2c1 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ ++ tps: tps@24 { ++ reg = <0x24>; ++ }; ++ ++ baseboard_eeprom: baseboard_eeprom@50 { ++ compatible = "at,24c256"; ++ reg = <0x50>; ++ }; ++ ++}; ++ ++&i2c3 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c3_pins>; ++ ++ clock-frequency = <100000>; ++ ++ /* OK, I know these are cape but for now it will do */ ++ cape_eeprom_0: cape_eeprom_0@54 { ++ compatible = "at,24c256"; ++ reg = <0x54>; ++ }; ++ ++ cape_eeprom_1: cape_eeprom_1@55 { ++ compatible = "at,24c256"; ++ reg = <0x55>; ++ }; ++ ++ cape_eeprom_2: cape_eeprom_2@56 { ++ compatible = "at,24c256"; ++ reg = <0x56>; ++ }; ++ ++ cape_eeprom_3: cape_eeprom_3@57 { ++ compatible = "at,24c256"; ++ reg = <0x57>; ++ }; ++}; ++ + /include/ "tps65217.dtsi" + + &tps { diff --git a/patches/linux-3.7-rc6/0071-am33xx-Convert-I2C-from-omap-to-am33xx-names.patch b/patches/linux-3.7-rc6/0071-am33xx-Convert-I2C-from-omap-to-am33xx-names.patch new file mode 100644 index 0000000..007caf1 --- /dev/null +++ b/patches/linux-3.7-rc6/0071-am33xx-Convert-I2C-from-omap-to-am33xx-names.patch @@ -0,0 +1,107 @@ +From bd2807f5f8e0cf858f95e7d930de4aec2d753d4c Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Sat, 15 Sep 2012 14:49:11 +0300 +Subject: [PATCH] am33xx: Convert I2C from omap to am33xx names + +On OMAP the TRM names I2C instances as i2c1, i2c2, etc. +On the am33xx's it is i2c0, i2c1, etc. + +Use am33xx naming everywhere, beside the hwmod name. +--- + arch/arm/boot/dts/am335x-bone.dts | 8 ++++---- + arch/arm/boot/dts/am335x-evm.dts | 2 +- + arch/arm/boot/dts/am33xx.dtsi | 12 ++++++------ + 3 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts +index d1c21ba..1daf1af 100644 +--- a/arch/arm/boot/dts/am335x-bone.dts ++++ b/arch/arm/boot/dts/am335x-bone.dts +@@ -52,7 +52,7 @@ + 0x60 0x17 /* gpmc_a8.gpio1_24, OUTPUT_PULLUP | MODE7 */ + >; + }; +- i2c3_pins: pinmux_i2c3_pins { ++ i2c2_pins: pinmux_i2c2_pins { + pinctrl-single,pins = < + 0x178 0x73 /* uart1_ctsn.i2c2_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */ + 0x17c 0x73 /* uart1_rtsn.i2c2_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */ +@@ -109,7 +109,7 @@ + }; + }; + +-&i2c1 { ++&i2c0 { + status = "okay"; + clock-frequency = <400000>; + +@@ -124,10 +124,10 @@ + + }; + +-&i2c3 { ++&i2c2 { + status = "okay"; + pinctrl-names = "default"; +- pinctrl-0 = <&i2c3_pins>; ++ pinctrl-0 = <&i2c2_pins>; + + clock-frequency = <100000>; + +diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts +index 43e23a8..6032648 100644 +--- a/arch/arm/boot/dts/am335x-evm.dts ++++ b/arch/arm/boot/dts/am335x-evm.dts +@@ -29,7 +29,7 @@ + status = "okay"; + }; + +- i2c1: i2c@44e0b000 { ++ i2c0: i2c@44e0b000 { + status = "okay"; + clock-frequency = <400000>; + +diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi +index 433065e..535a66c 100644 +--- a/arch/arm/boot/dts/am33xx.dtsi ++++ b/arch/arm/boot/dts/am33xx.dtsi +@@ -225,33 +225,33 @@ + status = "disabled"; + }; + +- i2c1: i2c@44e0b000 { ++ i2c0: i2c@44e0b000 { + compatible = "ti,omap4-i2c"; + #address-cells = <1>; + #size-cells = <0>; +- ti,hwmods = "i2c1"; ++ ti,hwmods = "i2c1"; /* TODO: Fix hwmod */ + reg = <0x44e0b000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <70>; + status = "disabled"; + }; + +- i2c2: i2c@4802a000 { ++ i2c1: i2c@4802a000 { + compatible = "ti,omap4-i2c"; + #address-cells = <1>; + #size-cells = <0>; +- ti,hwmods = "i2c2"; ++ ti,hwmods = "i2c2"; /* TODO: Fix hwmod */ + reg = <0x4802a000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <71>; + status = "disabled"; + }; + +- i2c3: i2c@4819c000 { ++ i2c2: i2c@4819c000 { + compatible = "ti,omap4-i2c"; + #address-cells = <1>; + #size-cells = <0>; +- ti,hwmods = "i2c3"; ++ ti,hwmods = "i2c3"; /* TODO: Fix hwmod */ + reg = <0x4819c000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <30>; diff --git a/patches/linux-3.7-rc6/0072-beaglebone-fix-backlight-entry-in-DT.patch b/patches/linux-3.7-rc6/0072-beaglebone-fix-backlight-entry-in-DT.patch new file mode 100644 index 0000000..58f62c9 --- /dev/null +++ b/patches/linux-3.7-rc6/0072-beaglebone-fix-backlight-entry-in-DT.patch @@ -0,0 +1,29 @@ +From b1eb01e79784564526df857c50491fcd47a124b5 Mon Sep 17 00:00:00 2001 +From: Koen Kooi <koen@dominion.thruhere.net> +Date: Tue, 18 Sep 2012 11:23:47 +0200 +Subject: [PATCH] beaglebone: fix backlight entry in DT + +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/boot/dts/am335x-bone.dts | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts +index 1daf1af..667842d 100644 +--- a/arch/arm/boot/dts/am335x-bone.dts ++++ b/arch/arm/boot/dts/am335x-bone.dts +@@ -107,6 +107,14 @@ + gpio-evt = <&gpio3 2 0>; + }; + }; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&ehrpwm1 0 500000 0>; ++ pwm-names = "st7735fb"; ++ brightness-levels = <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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100>; ++ default-brightness-level = <50>; /* index to the array above */ ++ }; + }; + + &i2c0 { diff --git a/patches/linux-3.7-rc6/0074-Shut-up-musb.patch b/patches/linux-3.7-rc6/0074-Shut-up-musb.patch new file mode 100644 index 0000000..e533862 --- /dev/null +++ b/patches/linux-3.7-rc6/0074-Shut-up-musb.patch @@ -0,0 +1,24 @@ +From f52622777ab0362a9b6abe4a781ea3138285cb91 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Thu, 4 Oct 2012 12:02:13 +0300 +Subject: [PATCH] Shut up musb! + +--- + drivers/usb/musb/musb_host.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c +index 3df6a76..f43b55c 100644 +--- a/drivers/usb/musb/musb_host.c ++++ b/drivers/usb/musb/musb_host.c +@@ -2432,8 +2432,10 @@ static int musb_bus_suspend(struct usb_hcd *hcd) + } + + if (musb->is_active) { ++#if 0 + WARNING("trying to suspend as %s while active\n", + otg_state_string(musb->xceiv->state)); ++#endif + return -EBUSY; + } else + return 0; diff --git a/patches/linux-3.7-rc6/0075-musb-Fix-crashes-and-other-weirdness.patch b/patches/linux-3.7-rc6/0075-musb-Fix-crashes-and-other-weirdness.patch new file mode 100644 index 0000000..6febda8 --- /dev/null +++ b/patches/linux-3.7-rc6/0075-musb-Fix-crashes-and-other-weirdness.patch @@ -0,0 +1,46 @@ +From 51880a937820eeb67105545a7202668c1b2a4663 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Thu, 4 Oct 2012 17:53:53 +0300 +Subject: [PATCH] musb: Fix crashes, and other weirdness. + +--- + arch/arm/boot/dts/am33xx.dtsi | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi +index 535a66c..9bb71cb 100644 +--- a/arch/arm/boot/dts/am33xx.dtsi ++++ b/arch/arm/boot/dts/am33xx.dtsi +@@ -285,6 +285,32 @@ + status = "disabled"; + }; + ++ usb0_phy: phy0 { ++ compatible = "nop-xceiv-usb"; ++ }; ++ ++ usb1_phy: phy1 { ++ compatible = "nop-xceiv-usb"; ++ }; ++ ++ usb_otg_hs: usb_otg_hs { ++ compatible = "ti,musb-am33xx"; ++ ti,hwmods = "usb_otg_hs"; ++ multipoint = <1>; ++ num-eps = <16>; ++ ram-bits = <12>; ++ port0-mode = <3>; ++ port1-mode = <1>; ++ power = <250>; ++ usb0-phy = <&usb0_phy>; ++ usb1-phy = <&usb1_phy>; ++ }; ++ ++ rtc { ++ compatible = "ti,da830-rtc"; ++ ti,hwmods = "rtc"; ++ }; ++ + spi0: spi@48030000 { + compatible = "ti,omap4-mcspi"; + ti,hwmods = "spi0"; diff --git a/patches/linux-3.7-rc6/0076-musb-revert-parts-of-032ec49f.patch b/patches/linux-3.7-rc6/0076-musb-revert-parts-of-032ec49f.patch new file mode 100644 index 0000000..6b3083e --- /dev/null +++ b/patches/linux-3.7-rc6/0076-musb-revert-parts-of-032ec49f.patch @@ -0,0 +1,371 @@ +From 482b626629b125679eab02d90e067e1223201506 Mon Sep 17 00:00:00 2001 +From: Daniel Mack <zonque@gmail.com> +Date: Wed, 17 Oct 2012 15:34:24 +0200 +Subject: [PATCH] musb: revert parts of 032ec49f + +This reverts parts of commit 032ec49f ("usb: musb: drop useless +board_mode usage") to get USB host mode working again. +--- + drivers/usb/musb/musb_core.c | 210 ++++++++++++++++++++++++++++-------------- + drivers/usb/musb/musb_core.h | 5 + + 2 files changed, 144 insertions(+), 71 deletions(-) + +diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c +index bb56a0e..8621fca 100644 +--- a/drivers/usb/musb/musb_core.c ++++ b/drivers/usb/musb/musb_core.c +@@ -681,7 +681,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, + break; + case OTG_STATE_B_PERIPHERAL: + musb_g_suspend(musb); +- musb->is_active = otg->gadget->b_hnp_enable; ++ musb->is_active = is_otg_enabled(musb) ++ && otg->gadget->b_hnp_enable; + if (musb->is_active) { + musb->xceiv->state = OTG_STATE_B_WAIT_ACON; + dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n"); +@@ -697,7 +698,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, + break; + case OTG_STATE_A_HOST: + musb->xceiv->state = OTG_STATE_A_SUSPEND; +- musb->is_active = otg->host->b_hnp_enable; ++ musb->is_active = is_otg_enabled(musb) ++ && otg->host->b_hnp_enable; + break; + case OTG_STATE_B_HOST: + /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ +@@ -785,7 +787,7 @@ b_host: + case OTG_STATE_A_SUSPEND: + usb_hcd_resume_root_hub(musb_to_hcd(musb)); + musb_root_disconnect(musb); +- if (musb->a_wait_bcon != 0) ++ if (musb->a_wait_bcon != 0 && is_otg_enabled(musb)) + musb_platform_try_idle(musb, jiffies + + msecs_to_jiffies(musb->a_wait_bcon)); + break; +@@ -961,16 +963,25 @@ void musb_start(struct musb *musb) + devctl = musb_readb(regs, MUSB_DEVCTL); + devctl &= ~MUSB_DEVCTL_SESSION; + +- /* session started after: +- * (a) ID-grounded irq, host mode; +- * (b) vbus present/connect IRQ, peripheral mode; +- * (c) peripheral initiates, using SRP +- */ +- if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) +- musb->is_active = 1; +- else ++ if (is_otg_enabled(musb)) { ++ /* session started after: ++ * (a) ID-grounded irq, host mode; ++ * (b) vbus present/connect IRQ, peripheral mode; ++ * (c) peripheral initiates, using SRP ++ */ ++ if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) ++ musb->is_active = 1; ++ else ++ devctl |= MUSB_DEVCTL_SESSION; ++ ++ } else if (is_host_enabled(musb)) { ++ /* assume ID pin is hard-wired to ground */ + devctl |= MUSB_DEVCTL_SESSION; + ++ } else /* peripheral is enabled */ { ++ if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) ++ musb->is_active = 1; ++ } + musb_platform_enable(musb); + musb_writeb(regs, MUSB_DEVCTL, devctl); + } +@@ -1034,6 +1045,8 @@ static void musb_shutdown(struct platform_device *pdev) + musb_generic_disable(musb); + spin_unlock_irqrestore(&musb->lock, flags); + ++ if (!is_otg_enabled(musb) && is_host_enabled(musb)) ++ usb_remove_hcd(musb_to_hcd(musb)); + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); + musb_platform_exit(musb); + +@@ -1891,7 +1904,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) + int status; + struct musb *musb; + struct musb_hdrc_platform_data *plat = dev->platform_data; +- struct usb_hcd *hcd; + + /* The driver might handle more features than the board; OK. + * Fail when the board needs a feature that's not enabled. +@@ -1914,6 +1926,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) + pm_runtime_enable(musb->controller); + + spin_lock_init(&musb->lock); ++ musb->board_mode = plat->mode; + musb->board_set_power = plat->set_power; + musb->min_power = plat->min_power; + musb->ops = plat->platform_ops; +@@ -1984,7 +1997,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) + goto fail3; + } + musb->nIrq = nIrq; +- /* FIXME this handles wakeup irqs wrong */ ++/* FIXME this handles wakeup irqs wrong */ + if (enable_irq_wake(nIrq) == 0) { + musb->irq_wake = 1; + device_init_wakeup(dev, 1); +@@ -1993,25 +2006,58 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) + } + + /* host side needs more setup */ +- hcd = musb_to_hcd(musb); +- otg_set_host(musb->xceiv->otg, &hcd->self); +- hcd->self.otg_port = 1; +- musb->xceiv->otg->host = &hcd->self; +- hcd->power_budget = 2 * (plat->power ? : 250); +- +- /* program PHY to use external vBus if required */ +- if (plat->extvbus) { +- u8 busctl = musb_read_ulpi_buscontrol(musb->mregs); +- busctl |= MUSB_ULPI_USE_EXTVBUS; +- musb_write_ulpi_buscontrol(musb->mregs, busctl); ++ if (is_host_enabled(musb)) { ++ struct usb_hcd *hcd = musb_to_hcd(musb); ++ ++ otg_set_host(musb->xceiv->otg, &hcd->self); ++ ++ if (is_otg_enabled(musb)) ++ hcd->self.otg_port = 1; ++ musb->xceiv->otg->host = &hcd->self; ++ hcd->power_budget = 2 * (plat->power ? : 250); ++ ++ /* program PHY to use external vBus if required */ ++ if (plat->extvbus) { ++ u8 busctl = musb_read_ulpi_buscontrol(musb->mregs); ++ busctl |= MUSB_ULPI_USE_EXTVBUS; ++ musb_write_ulpi_buscontrol(musb->mregs, busctl); ++ } + } + +- MUSB_DEV_MODE(musb); +- musb->xceiv->otg->default_a = 0; +- musb->xceiv->state = OTG_STATE_B_IDLE; ++ /* For the host-only role, we can activate right away. ++ * (We expect the ID pin to be forcibly grounded!!) ++ * Otherwise, wait till the gadget driver hooks up. ++ */ ++ if (!is_otg_enabled(musb) && is_host_enabled(musb)) { ++ struct usb_hcd *hcd = musb_to_hcd(musb); ++ ++ MUSB_HST_MODE(musb); ++ musb->xceiv->otg->default_a = 1; ++ musb->xceiv->state = OTG_STATE_A_IDLE; ++ ++ status = usb_add_hcd(musb_to_hcd(musb), 0, 0); ++ ++ hcd->self.uses_pio_for_control = 1; ++ dev_dbg(musb->controller, "%s mode, status %d, devctl %02x %c\n", ++ "HOST", status, ++ musb_readb(musb->mregs, MUSB_DEVCTL), ++ (musb_readb(musb->mregs, MUSB_DEVCTL) ++ & MUSB_DEVCTL_BDEVICE ++ ? 'B' : 'A')); ++ ++ } else /* peripheral is enabled */ { ++ MUSB_DEV_MODE(musb); ++ musb->xceiv->otg->default_a = 0; ++ musb->xceiv->state = OTG_STATE_B_IDLE; ++ ++ status = musb_gadget_setup(musb); + +- status = musb_gadget_setup(musb); ++ dev_dbg(musb->controller, "%s mode, status %d, dev%02x\n", ++ is_otg_enabled(musb) ? "OTG" : "PERIPHERAL", ++ status, ++ musb_readb(musb->mregs, MUSB_DEVCTL)); + ++ } + if (status < 0) + goto fail3; + +@@ -2027,13 +2073,28 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) + + pm_runtime_put(musb->controller); + ++ dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n", ++ ({char *s; ++ switch (musb->board_mode) { ++ case MUSB_HOST: s = "Host"; break; ++ case MUSB_PERIPHERAL: s = "Peripheral"; break; ++ default: s = "OTG"; break; ++ }; s; }), ++ ctrl, ++ (is_dma_capable() && musb->dma_controller) ++ ? "DMA" : "PIO", ++ musb->nIrq); ++ + return 0; + + fail5: + musb_exit_debugfs(musb); + + fail4: +- musb_gadget_cleanup(musb); ++ if (!is_otg_enabled(musb) && is_host_enabled(musb)) ++ usb_remove_hcd(musb_to_hcd(musb)); ++ else ++ musb_gadget_cleanup(musb); + + fail3: + pm_runtime_put_sync(musb->controller); +@@ -2116,9 +2177,11 @@ static void musb_save_context(struct musb *musb) + void __iomem *musb_base = musb->mregs; + void __iomem *epio; + +- musb->context.frame = musb_readw(musb_base, MUSB_FRAME); +- musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE); +- musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs); ++ if (is_host_enabled(musb)) { ++ musb->context.frame = musb_readw(musb_base, MUSB_FRAME); ++ musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE); ++ musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs); ++ } + musb->context.power = musb_readb(musb_base, MUSB_POWER); + musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE); + musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE); +@@ -2157,29 +2220,30 @@ static void musb_save_context(struct musb *musb) + musb->context.index_regs[i].rxfifosz = + musb_read_rxfifosz(musb_base); + } +- +- musb->context.index_regs[i].txtype = +- musb_readb(epio, MUSB_TXTYPE); +- musb->context.index_regs[i].txinterval = +- musb_readb(epio, MUSB_TXINTERVAL); +- musb->context.index_regs[i].rxtype = +- musb_readb(epio, MUSB_RXTYPE); +- musb->context.index_regs[i].rxinterval = +- musb_readb(epio, MUSB_RXINTERVAL); +- +- musb->context.index_regs[i].txfunaddr = +- musb_read_txfunaddr(musb_base, i); +- musb->context.index_regs[i].txhubaddr = +- musb_read_txhubaddr(musb_base, i); +- musb->context.index_regs[i].txhubport = +- musb_read_txhubport(musb_base, i); +- +- musb->context.index_regs[i].rxfunaddr = +- musb_read_rxfunaddr(musb_base, i); +- musb->context.index_regs[i].rxhubaddr = +- musb_read_rxhubaddr(musb_base, i); +- musb->context.index_regs[i].rxhubport = +- musb_read_rxhubport(musb_base, i); ++ if (is_host_enabled(musb)) { ++ musb->context.index_regs[i].txtype = ++ musb_readb(epio, MUSB_TXTYPE); ++ musb->context.index_regs[i].txinterval = ++ musb_readb(epio, MUSB_TXINTERVAL); ++ musb->context.index_regs[i].rxtype = ++ musb_readb(epio, MUSB_RXTYPE); ++ musb->context.index_regs[i].rxinterval = ++ musb_readb(epio, MUSB_RXINTERVAL); ++ ++ musb->context.index_regs[i].txfunaddr = ++ musb_read_txfunaddr(musb_base, i); ++ musb->context.index_regs[i].txhubaddr = ++ musb_read_txhubaddr(musb_base, i); ++ musb->context.index_regs[i].txhubport = ++ musb_read_txhubport(musb_base, i); ++ ++ musb->context.index_regs[i].rxfunaddr = ++ musb_read_rxfunaddr(musb_base, i); ++ musb->context.index_regs[i].rxhubaddr = ++ musb_read_rxhubaddr(musb_base, i); ++ musb->context.index_regs[i].rxhubport = ++ musb_read_rxhubport(musb_base, i); ++ } + } + } + +@@ -2190,9 +2254,11 @@ static void musb_restore_context(struct musb *musb) + void __iomem *ep_target_regs; + void __iomem *epio; + +- musb_writew(musb_base, MUSB_FRAME, musb->context.frame); +- musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode); +- musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); ++ if (is_host_enabled(musb)) { ++ musb_writew(musb_base, MUSB_FRAME, musb->context.frame); ++ musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode); ++ musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); ++ } + musb_writeb(musb_base, MUSB_POWER, musb->context.power); + musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe); + musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe); +@@ -2231,31 +2297,33 @@ static void musb_restore_context(struct musb *musb) + musb->context.index_regs[i].rxfifoadd); + } + +- musb_writeb(epio, MUSB_TXTYPE, ++ if (is_host_enabled(musb)) { ++ musb_writeb(epio, MUSB_TXTYPE, + musb->context.index_regs[i].txtype); +- musb_writeb(epio, MUSB_TXINTERVAL, ++ musb_writeb(epio, MUSB_TXINTERVAL, + musb->context.index_regs[i].txinterval); +- musb_writeb(epio, MUSB_RXTYPE, ++ musb_writeb(epio, MUSB_RXTYPE, + musb->context.index_regs[i].rxtype); +- musb_writeb(epio, MUSB_RXINTERVAL, ++ musb_writeb(epio, MUSB_RXINTERVAL, + +- musb->context.index_regs[i].rxinterval); +- musb_write_txfunaddr(musb_base, i, ++ musb->context.index_regs[i].rxinterval); ++ musb_write_txfunaddr(musb_base, i, + musb->context.index_regs[i].txfunaddr); +- musb_write_txhubaddr(musb_base, i, ++ musb_write_txhubaddr(musb_base, i, + musb->context.index_regs[i].txhubaddr); +- musb_write_txhubport(musb_base, i, ++ musb_write_txhubport(musb_base, i, + musb->context.index_regs[i].txhubport); + +- ep_target_regs = +- musb_read_target_reg_base(i, musb_base); ++ ep_target_regs = ++ musb_read_target_reg_base(i, musb_base); + +- musb_write_rxfunaddr(ep_target_regs, ++ musb_write_rxfunaddr(ep_target_regs, + musb->context.index_regs[i].rxfunaddr); +- musb_write_rxhubaddr(ep_target_regs, ++ musb_write_rxhubaddr(ep_target_regs, + musb->context.index_regs[i].rxhubaddr); +- musb_write_rxhubport(ep_target_regs, ++ musb_write_rxhubport(ep_target_regs, + musb->context.index_regs[i].rxhubport); ++ } + } + musb_writeb(musb_base, MUSB_INDEX, musb->context.index); + } +diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h +index c158aac..290e411 100644 +--- a/drivers/usb/musb/musb_core.h ++++ b/drivers/usb/musb/musb_core.h +@@ -71,6 +71,10 @@ struct musb_ep; + #include <linux/usb/hcd.h> + #include "musb_host.h" + ++#define is_peripheral_enabled(musb) ((musb)->board_mode != MUSB_HOST) ++#define is_host_enabled(musb) ((musb)->board_mode != MUSB_PERIPHERAL) ++#define is_otg_enabled(musb) ((musb)->board_mode == MUSB_OTG) ++ + /* NOTE: otg and peripheral-only state machines start at B_IDLE. + * OTG or host-only go to A_IDLE when ID is sensed. + */ +@@ -368,6 +372,7 @@ struct musb { + u16 epmask; + u8 nr_endpoints; + ++ u8 board_mode; /* enum musb_mode */ + int (*board_set_power)(int state); + + u8 min_power; /* vbus for periph, in mA/2 */ diff --git a/patches/linux-3.7-rc6/0077-usb-musb-dsps-get-the-PHY-using-phandle-api.patch b/patches/linux-3.7-rc6/0077-usb-musb-dsps-get-the-PHY-using-phandle-api.patch new file mode 100644 index 0000000..ec0953e --- /dev/null +++ b/patches/linux-3.7-rc6/0077-usb-musb-dsps-get-the-PHY-using-phandle-api.patch @@ -0,0 +1,55 @@ +From f2a9a492881a8eb7b4e9368510e29bcf04e16adb Mon Sep 17 00:00:00 2001 +From: Ravi Babu <ravibabu@ti.com> +Date: Thu, 2 Aug 2012 16:13:32 +0530 +Subject: [PATCH] usb: musb: dsps: get the PHY using phandle api + +AM33xx has two PHY of same type used by each musb controller so +use phandle of phy nodes to get the phy pointer. + +Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> +Signed-off-by: Ravi Babu <ravibabu@ti.com> +--- + Documentation/devicetree/bindings/usb/am33xx-usb.txt | 5 +++++ + drivers/usb/musb/musb_dsps.c | 5 ++++- + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/usb/am33xx-usb.txt b/Documentation/devicetree/bindings/usb/am33xx-usb.txt +index ca8fa56..e2702df 100644 +--- a/Documentation/devicetree/bindings/usb/am33xx-usb.txt ++++ b/Documentation/devicetree/bindings/usb/am33xx-usb.txt +@@ -12,3 +12,8 @@ AM33XX MUSB GLUE + represents PERIPHERAL. + - power : Should be "250". This signifies the controller can supply upto + 500mA when operating in host mode. ++ - usb0-phy : phandle for usb0 NOP PHY ++ - usb1-phy : phandle for usb1 NOP PHY ++ ++NOP USB PHY ++ - compatible : Should be "nop-xceiv-usb" +diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c +index ff5f112..6a14101 100644 +--- a/drivers/usb/musb/musb_dsps.c ++++ b/drivers/usb/musb/musb_dsps.c +@@ -367,10 +367,12 @@ static int dsps_musb_init(struct musb *musb) + struct device *dev = musb->controller; + struct musb_hdrc_platform_data *plat = dev->platform_data; + struct platform_device *pdev = to_platform_device(dev); ++ struct platform_device *parent_pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = dev_get_drvdata(dev->parent); + const struct dsps_musb_wrapper *wrp = glue->wrp; + struct omap_musb_board_data *data = plat->board_data; + void __iomem *reg_base = musb->ctrl_base; ++ char name[10]; + u32 rev, val; + int status; + +@@ -378,7 +380,8 @@ static int dsps_musb_init(struct musb *musb) + musb->mregs += wrp->musb_core_offset; + + /* Get the NOP PHY */ +- musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); ++ sprintf(name, "usb%d-phy", pdev->id); ++ musb->xceiv = devm_usb_get_phy_by_phandle(&parent_pdev->dev, name); + if (IS_ERR_OR_NULL(musb->xceiv)) + return -ENODEV; + diff --git a/patches/linux-3.7-rc6/0078-drivers-usb-otg-add-device-tree-support-to-otg-libra.patch b/patches/linux-3.7-rc6/0078-drivers-usb-otg-add-device-tree-support-to-otg-libra.patch new file mode 100644 index 0000000..4ef518d --- /dev/null +++ b/patches/linux-3.7-rc6/0078-drivers-usb-otg-add-device-tree-support-to-otg-libra.patch @@ -0,0 +1,204 @@ +From 5a2e1bc30bd48edd71c3eaef3d5141d6fbe3edb2 Mon Sep 17 00:00:00 2001 +From: Ajay Kumar Gupta <ajay.gupta@ti.com> +Date: Tue, 10 Jul 2012 14:10:38 +0530 +Subject: [PATCH] drivers: usb: otg: add device tree support to otg library + +Adds an API to get usb phy by passing a device node phandle value. Since +now it's possible to obtain phy by phandle, the checks in usb_add_phy +for a valid phy type is removed (now it's just a debug message if a user +tries to add a phy with undefined type). +This also allows to add multiple phys of same type. + +Cc: Richard Zhao <richard.zhao@freescale.com> +Cc: Marek Vasut <marex@denx.de> +Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> +Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> +--- + drivers/usb/otg/otg.c | 95 ++++++++++++++++++++++++++++++++++++++++------- + include/linux/usb/otg.h | 32 ++++++++++++++++ + 2 files changed, 113 insertions(+), 14 deletions(-) + +diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c +index a30c041..ff08b34 100644 +--- a/drivers/usb/otg/otg.c ++++ b/drivers/usb/otg/otg.c +@@ -14,6 +14,7 @@ + #include <linux/err.h> + #include <linux/device.h> + #include <linux/slab.h> ++#include <linux/of.h> + + #include <linux/usb/otg.h> + +@@ -35,6 +36,21 @@ static struct usb_phy *__usb_find_phy(struct list_head *list, + return ERR_PTR(-ENODEV); + } + ++static struct usb_phy *__of_usb_find_phy(struct list_head *list, ++ struct device_node *node) ++{ ++ struct usb_phy *phy; ++ ++ list_for_each_entry(phy, list, head) { ++ if (node != phy->dev->of_node) ++ continue; ++ ++ return phy; ++ } ++ ++ return ERR_PTR(-ENODEV); ++} ++ + static void devm_usb_phy_release(struct device *dev, void *res) + { + struct usb_phy *phy = *(struct usb_phy **)res; +@@ -111,6 +127,65 @@ err0: + EXPORT_SYMBOL(usb_get_phy); + + /** ++ * devm_usb_get_phy_by_phandle - find the USB PHY by phandle ++ * @dev - device that requests this phy ++ * @phandle - name of the property holding the phy phandle value ++ * ++ * Returns the phy driver associated with the given phandle value, ++ * after getting a refcount to it; or -ENODEV/NULL if there is no such phy. ++ * While at that, it also associates the device with the phy using ++ * devres. On driver detach, release function is invoked on the devres data, ++ * then, devres data is freed. ++ * ++ * For use by USB host and peripheral drivers. ++ */ ++struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, ++ const char *phandle) ++{ ++ struct usb_phy *phy = NULL, **ptr; ++ unsigned long flags; ++ struct device_node *node; ++ ++ if (!dev->of_node) { ++ dev_dbg(dev, "device does not have a device node entry\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); ++ if (!ptr) { ++ dev_dbg(dev, "failed to allocate memory for devres\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ spin_lock_irqsave(&phy_lock, flags); ++ ++ node = of_parse_phandle(dev->of_node, phandle, 0); ++ if (!node) { ++ dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, ++ dev->of_node->full_name); ++ goto err0; ++ } ++ ++ phy = __of_usb_find_phy(&phy_list, node); ++ if (!IS_ERR(phy)) { ++ *ptr = phy; ++ devres_add(dev, ptr); ++ } else { ++ pr_err("unable to find transceiver with phandle %s\n", phandle); ++ devres_free(ptr); ++ goto err0; ++ } ++ ++ get_device(phy->dev); ++ ++err0: ++ spin_unlock_irqrestore(&phy_lock, flags); ++ ++ return phy; ++} ++EXPORT_SYMBOL(devm_usb_get_phy_by_phandle); ++ ++/** + * devm_usb_put_phy - release the USB PHY + * @dev - device that wants to release this phy + * @phy - the phy returned by devm_usb_get_phy() +@@ -155,32 +230,24 @@ EXPORT_SYMBOL(usb_put_phy); + */ + int usb_add_phy(struct usb_phy *x, enum usb_phy_type type) + { +- int ret = 0; + unsigned long flags; + struct usb_phy *phy; + +- if (x->type != USB_PHY_TYPE_UNDEFINED) { +- dev_err(x->dev, "not accepting initialized PHY %s\n", x->label); +- return -EINVAL; +- } ++ if (x && x->type != USB_PHY_TYPE_UNDEFINED) ++ dev_dbg(x->dev, "add a phy with undefined type %s\n", x->label); + + spin_lock_irqsave(&phy_lock, flags); + +- list_for_each_entry(phy, &phy_list, head) { +- if (phy->type == type) { +- ret = -EBUSY; +- dev_err(x->dev, "transceiver type %s already exists\n", ++ list_for_each_entry(phy, &phy_list, head) ++ if (phy->type == type) ++ dev_dbg(x->dev, "transceiver type %s already exists\n", + usb_phy_type_string(type)); +- goto out; +- } +- } + + x->type = type; + list_add_tail(&x->head, &phy_list); + +-out: + spin_unlock_irqrestore(&phy_lock, flags); +- return ret; ++ return 0; + } + EXPORT_SYMBOL(usb_add_phy); + +diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h +index e8a5fe8..bae7599 100644 +--- a/include/linux/usb/otg.h ++++ b/include/linux/usb/otg.h +@@ -37,8 +37,40 @@ struct usb_otg { + }; + + #ifdef CONFIG_USB_OTG_UTILS ++extern struct usb_phy *usb_get_phy(enum usb_phy_type type); ++extern struct usb_phy *devm_usb_get_phy(struct device *dev, ++ enum usb_phy_type type); ++extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, ++ const char *phandle); ++extern void usb_put_phy(struct usb_phy *); ++extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); + extern const char *otg_state_string(enum usb_otg_state state); + #else ++static inline struct usb_phy *usb_get_phy(enum usb_phy_type type) ++{ ++ return NULL; ++} ++ ++static inline struct usb_phy *devm_usb_get_phy(struct device *dev, ++ enum usb_phy_type type) ++{ ++ return NULL; ++} ++ ++extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, ++ const char *phandle) ++{ ++ return NULL; ++} ++ ++static inline void usb_put_phy(struct usb_phy *x) ++{ ++} ++ ++static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x) ++{ ++} ++ + static inline const char *otg_state_string(enum usb_otg_state state) + { + return NULL; diff --git a/patches/linux-3.7-rc6/0079-usb-otg-nop-add-dt-support.patch b/patches/linux-3.7-rc6/0079-usb-otg-nop-add-dt-support.patch new file mode 100644 index 0000000..ac46e10 --- /dev/null +++ b/patches/linux-3.7-rc6/0079-usb-otg-nop-add-dt-support.patch @@ -0,0 +1,48 @@ +From fb37c173324d76c12dd1b0e7758f1e2012f6dabf Mon Sep 17 00:00:00 2001 +From: Ajay Kumar Gupta <ajay.gupta@ti.com> +Date: Tue, 10 Jul 2012 14:51:53 +0530 +Subject: [PATCH] usb: otg: nop: add dt support + +Added device tree support for nop transceiver driver and updated the +Documentation with device tree binding information for am33xx platform. + +Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> +Signed-off-by: Ravi Babu <ravibabu@ti.com> +--- + drivers/usb/otg/nop-usb-xceiv.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c +index e52e35e..466a321 100644 +--- a/drivers/usb/otg/nop-usb-xceiv.c ++++ b/drivers/usb/otg/nop-usb-xceiv.c +@@ -27,6 +27,7 @@ + */ + + #include <linux/module.h> ++#include <linux/of.h> + #include <linux/platform_device.h> + #include <linux/dma-mapping.h> + #include <linux/usb/otg.h> +@@ -154,12 +155,21 @@ static int __devexit nop_usb_xceiv_remove(struct platform_device *pdev) + return 0; + } + ++#ifdef CONFIG_OF ++static const struct of_device_id nop_xceiv_id_table[] = { ++ { .compatible = "nop-xceiv-usb" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, nop_xceiv_id_table); ++#endif ++ + static struct platform_driver nop_usb_xceiv_driver = { + .probe = nop_usb_xceiv_probe, + .remove = __devexit_p(nop_usb_xceiv_remove), + .driver = { + .name = "nop_usb_xceiv", + .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(nop_xceiv_id_table), + }, + }; + diff --git a/patches/linux-3.7-rc6/0080-usb-musb-dsps-add-phy-control-logic-to-glue.patch b/patches/linux-3.7-rc6/0080-usb-musb-dsps-add-phy-control-logic-to-glue.patch new file mode 100644 index 0000000..81953b7 --- /dev/null +++ b/patches/linux-3.7-rc6/0080-usb-musb-dsps-add-phy-control-logic-to-glue.patch @@ -0,0 +1,275 @@ +From eca00fad21c1ef2bf0df883fa2c001e2242bfe29 Mon Sep 17 00:00:00 2001 +From: Ajay Kumar Gupta <ajay.gupta@ti.com> +Date: Thu, 5 Jul 2012 14:06:42 +0530 +Subject: [PATCH] usb: musb: dsps: add phy control logic to glue + +AM335x uses NOP transceiver driver and need to enable builtin PHY +by writing into usb_ctrl register available in system control +module register space. This is being added at musb glue driver +layer untill a separate system control module driver is available. + +Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> +--- + arch/arm/mach-omap2/board-ti8168evm.c | 1 - + arch/arm/mach-omap2/omap_phy_internal.c | 35 ------------ + arch/arm/plat-omap/include/plat/usb.h | 5 +- + drivers/usb/musb/musb_dsps.c | 91 +++++++++++++++++++++++++------ + 4 files changed, 75 insertions(+), 57 deletions(-) + +diff --git a/arch/arm/mach-omap2/board-ti8168evm.c b/arch/arm/mach-omap2/board-ti8168evm.c +index c4f8833..b367d18 100644 +--- a/arch/arm/mach-omap2/board-ti8168evm.c ++++ b/arch/arm/mach-omap2/board-ti8168evm.c +@@ -23,7 +23,6 @@ + #include <plat/usb.h> + + static struct omap_musb_board_data musb_board_data = { +- .set_phy_power = ti81xx_musb_phy_power, + .interface_type = MUSB_INTERFACE_ULPI, + .mode = MUSB_OTG, + .power = 500, +diff --git a/arch/arm/mach-omap2/omap_phy_internal.c b/arch/arm/mach-omap2/omap_phy_internal.c +index d992db8..db3ada8 100644 +--- a/arch/arm/mach-omap2/omap_phy_internal.c ++++ b/arch/arm/mach-omap2/omap_phy_internal.c +@@ -118,38 +118,3 @@ void am35x_set_mode(u8 musb_mode) + + omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); + } +- +-void ti81xx_musb_phy_power(u8 on) +-{ +- void __iomem *scm_base = NULL; +- u32 usbphycfg; +- +- scm_base = ioremap(TI81XX_SCM_BASE, SZ_2K); +- if (!scm_base) { +- pr_err("system control module ioremap failed\n"); +- return; +- } +- +- usbphycfg = __raw_readl(scm_base + USBCTRL0); +- +- if (on) { +- if (cpu_is_ti816x()) { +- usbphycfg |= TI816X_USBPHY0_NORMAL_MODE; +- usbphycfg &= ~TI816X_USBPHY_REFCLK_OSC; +- } else if (cpu_is_ti814x()) { +- usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN +- | USBPHY_DPINPUT | USBPHY_DMINPUT); +- usbphycfg |= (USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN +- | USBPHY_DPOPBUFCTL | USBPHY_DMOPBUFCTL); +- } +- } else { +- if (cpu_is_ti816x()) +- usbphycfg &= ~TI816X_USBPHY0_NORMAL_MODE; +- else if (cpu_is_ti814x()) +- usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; +- +- } +- __raw_writel(usbphycfg, scm_base + USBCTRL0); +- +- iounmap(scm_base); +-} +diff --git a/arch/arm/plat-omap/include/plat/usb.h b/arch/arm/plat-omap/include/plat/usb.h +index 87ee140..43052e7f 100644 +--- a/arch/arm/plat-omap/include/plat/usb.h ++++ b/arch/arm/plat-omap/include/plat/usb.h +@@ -101,7 +101,6 @@ extern void am35x_musb_reset(void); + extern void am35x_musb_phy_power(u8 on); + extern void am35x_musb_clear_irq(void); + extern void am35x_set_mode(u8 musb_mode); +-extern void ti81xx_musb_phy_power(u8 on); + + /* AM35x */ + /* USB 2.0 PHY Control */ +@@ -126,8 +125,8 @@ extern void ti81xx_musb_phy_power(u8 on); + #define CONF2_DATPOL (1 << 1) + + /* TI81XX specific definitions */ +-#define USBCTRL0 0x620 +-#define USBSTAT0 0x624 ++#define MUSB_USBSS_REV_816X 0x9 ++#define MUSB_USBSS_REV_814X 0xb + + /* TI816X PHY controls bits */ + #define TI816X_USBPHY0_NORMAL_MODE (1 << 0) +diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c +index 6a14101..1151760 100644 +--- a/drivers/usb/musb/musb_dsps.c ++++ b/drivers/usb/musb/musb_dsps.c +@@ -124,9 +124,46 @@ struct dsps_glue { + const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ + struct timer_list timer[2]; /* otg_workaround timer */ + unsigned long last_timer[2]; /* last timer data for each instance */ ++ u32 __iomem *usb_ctrl[2]; ++ u8 usbss_rev; + }; + + /** ++ * musb_dsps_phy_control - phy on/off ++ * @glue: struct dsps_glue * ++ * @id: the id ++ * @on: flag for phy to be switched on or off ++ * ++ * This is to enable the PHY using usb_ctrl register in system control ++ * module space. ++ * ++ * XXX: This function will be removed once we have a seperate driver for ++ * control module ++ */ ++static void musb_dsps_phy_control(struct dsps_glue *glue, u8 id, u8 on) ++{ ++ u32 usbphycfg; ++ ++ usbphycfg = __raw_readl(glue->usb_ctrl[id]); ++ if (on) { ++ if (glue->usbss_rev == MUSB_USBSS_REV_816X) { ++ usbphycfg |= TI816X_USBPHY0_NORMAL_MODE; ++ usbphycfg &= ~TI816X_USBPHY_REFCLK_OSC; ++ } else if (glue->usbss_rev == MUSB_USBSS_REV_814X) { ++ usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN ++ | USBPHY_DPINPUT | USBPHY_DMINPUT); ++ usbphycfg |= (USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN ++ | USBPHY_DPOPBUFCTL | USBPHY_DMOPBUFCTL); ++ } ++ } else { ++ if (glue->usbss_rev == MUSB_USBSS_REV_816X) ++ usbphycfg &= ~TI816X_USBPHY0_NORMAL_MODE; ++ else if (glue->usbss_rev == MUSB_USBSS_REV_814X) ++ usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; ++ } ++ __raw_writel(usbphycfg, glue->usb_ctrl[id]); ++} ++/** + * dsps_musb_enable - enable interrupts + */ + static void dsps_musb_enable(struct musb *musb) +@@ -365,12 +402,10 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) + static int dsps_musb_init(struct musb *musb) + { + struct device *dev = musb->controller; +- struct musb_hdrc_platform_data *plat = dev->platform_data; + struct platform_device *pdev = to_platform_device(dev); + struct platform_device *parent_pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = dev_get_drvdata(dev->parent); + const struct dsps_musb_wrapper *wrp = glue->wrp; +- struct omap_musb_board_data *data = plat->board_data; + void __iomem *reg_base = musb->ctrl_base; + char name[10]; + u32 rev, val; +@@ -398,8 +433,7 @@ static int dsps_musb_init(struct musb *musb) + dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); + + /* Start the on-chip PHY and its PLL. */ +- if (data->set_phy_power) +- data->set_phy_power(1); ++ musb_dsps_phy_control(glue, pdev->id, 1); + + musb->isr = dsps_interrupt; + +@@ -421,16 +455,13 @@ err0: + static int dsps_musb_exit(struct musb *musb) + { + struct device *dev = musb->controller; +- struct musb_hdrc_platform_data *plat = dev->platform_data; +- struct omap_musb_board_data *data = plat->board_data; +- struct platform_device *pdev = to_platform_device(dev); +- struct dsps_glue *glue = dev_get_drvdata(dev->parent); ++ struct platform_device *pdev = to_platform_device(dev->parent); ++ struct dsps_glue *glue = platform_get_drvdata(pdev); + + del_timer_sync(&glue->timer[pdev->id]); + + /* Shutdown the on-chip PHY and its PLL. */ +- if (data->set_phy_power) +- data->set_phy_power(0); ++ musb_dsps_phy_control(glue, pdev->id, 0); + + /* NOP driver needs change if supporting dual instance */ + usb_put_phy(musb->xceiv); +@@ -464,6 +495,21 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) + char res_name[11]; + int ret, musbid; + ++ /* get memory resource for usb control register */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 2 * id + 2); ++ if (!res) { ++ dev_err(dev, "%s get mem resource failed\n", res_name); ++ ret = -ENODEV; ++ goto err0; ++ } ++ ++ glue->usb_ctrl[id] = devm_request_and_ioremap(&pdev->dev, res); ++ if (glue->usb_ctrl == NULL) { ++ dev_err(dev, "Failed to obtain usb_ctrl%d memory\n", id); ++ ret = -ENODEV; ++ goto err0; ++ } ++ + /* get memory resource */ + snprintf(res_name, sizeof(res_name), "musb%d", id); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); +@@ -579,6 +625,7 @@ static int __devinit dsps_probe(struct platform_device *pdev) + const struct dsps_musb_wrapper *wrp; + struct dsps_glue *glue; + struct resource *iomem; ++ u32 __iomem *usbss; + int ret, i; + + match = of_match_node(musb_dsps_of_match, np); +@@ -605,6 +652,13 @@ static int __devinit dsps_probe(struct platform_device *pdev) + goto err1; + } + ++ usbss = devm_request_and_ioremap(&pdev->dev, iomem); ++ if (usbss == NULL) { ++ dev_err(&pdev->dev, "Failed to obtain usbss memory\n"); ++ ret = -ENODEV; ++ goto err1; ++ } ++ + glue->dev = &pdev->dev; + + glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL); +@@ -636,6 +690,9 @@ static int __devinit dsps_probe(struct platform_device *pdev) + } + } + ++ /* read the usbss revision register */ ++ glue->usbss_rev = __raw_readl(usbss); ++ + return 0; + + err3: +@@ -669,24 +726,22 @@ static int __devexit dsps_remove(struct platform_device *pdev) + #ifdef CONFIG_PM_SLEEP + static int dsps_suspend(struct device *dev) + { +- struct musb_hdrc_platform_data *plat = dev->platform_data; +- struct omap_musb_board_data *data = plat->board_data; ++ struct platform_device *pdev = to_platform_device(dev->parent); ++ struct dsps_glue *glue = platform_get_drvdata(pdev); + + /* Shutdown the on-chip PHY and its PLL. */ +- if (data->set_phy_power) +- data->set_phy_power(0); ++ musb_dsps_phy_control(glue, pdev->id, 0); + + return 0; + } + + static int dsps_resume(struct device *dev) + { +- struct musb_hdrc_platform_data *plat = dev->platform_data; +- struct omap_musb_board_data *data = plat->board_data; ++ struct platform_device *pdev = to_platform_device(dev->parent); ++ struct dsps_glue *glue = platform_get_drvdata(pdev); + + /* Start the on-chip PHY and its PLL. */ +- if (data->set_phy_power) +- data->set_phy_power(1); ++ musb_dsps_phy_control(glue, pdev->id, 1); + + return 0; + } diff --git a/patches/linux-3.7-rc6/0081-usb-musb-dsps-enable-phy-control-for-am335x.patch b/patches/linux-3.7-rc6/0081-usb-musb-dsps-enable-phy-control-for-am335x.patch new file mode 100644 index 0000000..3935eb9 --- /dev/null +++ b/patches/linux-3.7-rc6/0081-usb-musb-dsps-enable-phy-control-for-am335x.patch @@ -0,0 +1,58 @@ +From 849303a736b86ac5de2570a52ddac5ef9c2290f0 Mon Sep 17 00:00:00 2001 +From: Ajay Kumar Gupta <ajay.gupta@ti.com> +Date: Thu, 5 Jul 2012 14:35:06 +0530 +Subject: [PATCH] usb: musb: dsps: enable phy control for am335x + +Enabled the phy control logic for am335x also based on usbss +revision register. + +Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> +--- + arch/arm/plat-omap/include/plat/usb.h | 1 + + drivers/usb/musb/musb_dsps.c | 17 +++++++++++------ + 2 files changed, 12 insertions(+), 6 deletions(-) + +diff --git a/arch/arm/plat-omap/include/plat/usb.h b/arch/arm/plat-omap/include/plat/usb.h +index 43052e7f..bb27e88 100644 +--- a/arch/arm/plat-omap/include/plat/usb.h ++++ b/arch/arm/plat-omap/include/plat/usb.h +@@ -127,6 +127,7 @@ extern void am35x_set_mode(u8 musb_mode); + /* TI81XX specific definitions */ + #define MUSB_USBSS_REV_816X 0x9 + #define MUSB_USBSS_REV_814X 0xb ++#define MUSB_USBSS_REV_33XX 0xd + + /* TI816X PHY controls bits */ + #define TI816X_USBPHY0_NORMAL_MODE (1 << 0) +diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c +index 1151760..ed3b379 100644 +--- a/drivers/usb/musb/musb_dsps.c ++++ b/drivers/usb/musb/musb_dsps.c +@@ -149,16 +149,21 @@ static void musb_dsps_phy_control(struct dsps_glue *glue, u8 id, u8 on) + if (glue->usbss_rev == MUSB_USBSS_REV_816X) { + usbphycfg |= TI816X_USBPHY0_NORMAL_MODE; + usbphycfg &= ~TI816X_USBPHY_REFCLK_OSC; +- } else if (glue->usbss_rev == MUSB_USBSS_REV_814X) { +- usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN +- | USBPHY_DPINPUT | USBPHY_DMINPUT); +- usbphycfg |= (USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN +- | USBPHY_DPOPBUFCTL | USBPHY_DMOPBUFCTL); ++ } else if (glue->usbss_rev == MUSB_USBSS_REV_814X || ++ glue->usbss_rev == MUSB_USBSS_REV_33XX) { ++ usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN); ++ usbphycfg |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; ++ if (glue->usbss_rev == MUSB_USBSS_REV_814X) { ++ usbphycfg &= ~(USBPHY_DPINPUT | USBPHY_DMINPUT); ++ usbphycfg |= USBPHY_DPOPBUFCTL ++ | USBPHY_DMOPBUFCTL; ++ } + } + } else { + if (glue->usbss_rev == MUSB_USBSS_REV_816X) + usbphycfg &= ~TI816X_USBPHY0_NORMAL_MODE; +- else if (glue->usbss_rev == MUSB_USBSS_REV_814X) ++ else if (glue->usbss_rev == MUSB_USBSS_REV_814X || ++ glue->usbss_rev == MUSB_USBSS_REV_33XX) + usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; + } + __raw_writel(usbphycfg, glue->usb_ctrl[id]); diff --git a/patches/linux-3.7-rc6/0082-ARM-am33xx-fix-mem-regions-in-USB-hwmod.patch b/patches/linux-3.7-rc6/0082-ARM-am33xx-fix-mem-regions-in-USB-hwmod.patch new file mode 100644 index 0000000..5fd84b3 --- /dev/null +++ b/patches/linux-3.7-rc6/0082-ARM-am33xx-fix-mem-regions-in-USB-hwmod.patch @@ -0,0 +1,45 @@ +From 23ec7954c2eb161d52ce3df4fac3f7a188319120 Mon Sep 17 00:00:00 2001 +From: Daniel Mack <zonque@gmail.com> +Date: Wed, 17 Oct 2012 16:39:00 +0200 +Subject: [PATCH] ARM: am33xx: fix mem regions in USB hwmod + +Signed-off-by: Daniel Mack <zonque@gmail.com> +--- + arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +index b6f78c1..2a5032f 100644 +--- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c ++++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +@@ -3310,12 +3310,24 @@ static struct omap_hwmod_addr_space am33xx_usbss_addr_space[] = { + .pa_end = 0x47401000 + SZ_2K - 1, + .flags = ADDR_TYPE_RT + }, +- { +- .name = "musb1", +- .pa_start = 0x47401800, +- .pa_end = 0x47401800 + SZ_2K - 1, +- .flags = ADDR_TYPE_RT +- }, ++ { ++ .name = "usb_ctrl0", ++ .pa_start = 0x44E10620, ++ .pa_end = 0x44E10620 + SZ_4 - 1, ++ .flags = ADDR_TYPE_RT ++ }, ++ { ++ .name = "musb1", ++ .pa_start = 0x47401800, ++ .pa_end = 0x47401800 + SZ_2K - 1, ++ .flags = ADDR_TYPE_RT ++ }, ++ { ++ .name = "usb_ctrl1", ++ .pa_start = 0x44E10628, ++ .pa_end = 0x44E10628 + SZ_4 - 1, ++ .flags = ADDR_TYPE_RT ++ }, + { } + }; + diff --git a/patches/linux-3.7-rc6/0084-omap2-clk-Add-missing-lcdc-clock-definition.patch b/patches/linux-3.7-rc6/0084-omap2-clk-Add-missing-lcdc-clock-definition.patch new file mode 100644 index 0000000..0e85066 --- /dev/null +++ b/patches/linux-3.7-rc6/0084-omap2-clk-Add-missing-lcdc-clock-definition.patch @@ -0,0 +1,40 @@ +From 5cb5d4cb5e66b2aab310bb097e23cd7b424c590d Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Sat, 13 Oct 2012 16:12:22 +0300 +Subject: [PATCH] omap2-clk: Add missing lcdc clock definition + +Looks like the lcdc clock definition got dropped. +It is required for the LCD controller to work. Reintroduce. +--- + arch/arm/mach-omap2/clock33xx_data.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/arch/arm/mach-omap2/clock33xx_data.c b/arch/arm/mach-omap2/clock33xx_data.c +index 1a45d6b..b7b7995 100644 +--- a/arch/arm/mach-omap2/clock33xx_data.c ++++ b/arch/arm/mach-omap2/clock33xx_data.c +@@ -867,6 +867,16 @@ static struct clk lcd_gclk = { + .recalc = &followparent_recalc, + }; + ++static struct clk lcdc_fck = { ++ .name = "lcdc_fck", ++ .clkdm_name = "lcdc_clkdm", ++ .parent = &lcd_gclk, ++ .enable_reg = AM33XX_CM_PER_LCDC_CLKCTRL, ++ .enable_bit = AM33XX_MODULEMODE_SWCTRL, ++ .ops = &clkops_omap2_dflt, ++ .recalc = &followparent_recalc, ++}; ++ + static struct clk mmc_clk = { + .name = "mmc_clk", + .clkdm_name = "l4ls_clkdm", +@@ -1075,6 +1085,7 @@ static struct omap_clk am33xx_clks[] = { + CLK(NULL, "clkout2_ck", &clkout2_ck, CK_AM33XX), + CLK(NULL, "timer_32k_ck", &clkdiv32k_ick, CK_AM33XX), + CLK(NULL, "timer_sys_ck", &sys_clkin_ck, CK_AM33XX), ++ CLK("da8xx_lcdc.0", NULL, &lcdc_fck, CK_AM33XX), + }; + + int __init am33xx_clk_init(void) diff --git a/patches/linux-3.7-rc6/0085-da8xx-Allow-use-by-am33xx-based-devices.patch b/patches/linux-3.7-rc6/0085-da8xx-Allow-use-by-am33xx-based-devices.patch new file mode 100644 index 0000000..f796803 --- /dev/null +++ b/patches/linux-3.7-rc6/0085-da8xx-Allow-use-by-am33xx-based-devices.patch @@ -0,0 +1,23 @@ +From a7cd16691ffbb0a9e4fe2d9602d51ae57d741753 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Sat, 13 Oct 2012 16:18:37 +0300 +Subject: [PATCH] da8xx: Allow use by am33xx based devices + +This driver can be used for AM33xx devices, like the popular beaglebone. +--- + drivers/video/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index 9791d10..e7868d8 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -2202,7 +2202,7 @@ config FB_SH7760 + + config FB_DA8XX + tristate "DA8xx/OMAP-L1xx Framebuffer support" +- depends on FB && ARCH_DAVINCI_DA8XX ++ depends on FB && (ARCH_DAVINCI_DA8XX || SOC_AM33XX) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT diff --git a/patches/linux-3.7-rc6/0086-da8xx-Fix-revision-check-on-the-da8xx-driver.patch b/patches/linux-3.7-rc6/0086-da8xx-Fix-revision-check-on-the-da8xx-driver.patch new file mode 100644 index 0000000..72d81c3 --- /dev/null +++ b/patches/linux-3.7-rc6/0086-da8xx-Fix-revision-check-on-the-da8xx-driver.patch @@ -0,0 +1,22 @@ +From fab03445e416c75fab4cbe2a46a241445965122f Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Sat, 13 Oct 2012 16:21:05 +0300 +Subject: [PATCH] da8xx: Fix revision check on the da8xx driver + +The revision check fails for the beaglebone; Add new revision ID. +--- + drivers/video/da8xx-fb.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c +index 80665f6..866d804 100644 +--- a/drivers/video/da8xx-fb.c ++++ b/drivers/video/da8xx-fb.c +@@ -1283,6 +1283,7 @@ static int __devinit fb_probe(struct platform_device *device) + lcd_revision = LCD_VERSION_1; + break; + case 0x4F200800: ++ case 0x4F201000: + lcd_revision = LCD_VERSION_2; + break; + default: diff --git a/patches/linux-3.7-rc6/0087-da8xx-De-constify-members-in-the-platform-config.patch b/patches/linux-3.7-rc6/0087-da8xx-De-constify-members-in-the-platform-config.patch new file mode 100644 index 0000000..d2773a9 --- /dev/null +++ b/patches/linux-3.7-rc6/0087-da8xx-De-constify-members-in-the-platform-config.patch @@ -0,0 +1,29 @@ +From d4638819046e8c3ea545eb8b63cc90466cd2dd1d Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Sat, 13 Oct 2012 16:22:47 +0300 +Subject: [PATCH] da8xx: De-constify members in the platform config. + +There's no need for this to be const. It interferes with +creating the platform data dynamically. + +Remove const. +--- + include/video/da8xx-fb.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/video/da8xx-fb.h b/include/video/da8xx-fb.h +index 5a0e4f9..a512d6b 100644 +--- a/include/video/da8xx-fb.h ++++ b/include/video/da8xx-fb.h +@@ -35,9 +35,9 @@ struct display_panel { + }; + + struct da8xx_lcdc_platform_data { +- const char manu_name[10]; ++ char manu_name[10]; + void *controller_data; +- const char type[25]; ++ char type[25]; + void (*panel_power_ctrl)(int); + }; + diff --git a/patches/linux-3.7-rc6/0088-da8xx-Add-standard-panel-definition.patch b/patches/linux-3.7-rc6/0088-da8xx-Add-standard-panel-definition.patch new file mode 100644 index 0000000..326ee0b --- /dev/null +++ b/patches/linux-3.7-rc6/0088-da8xx-Add-standard-panel-definition.patch @@ -0,0 +1,36 @@ +From 8267defaabc2e24f3e57a1804982905b11e4a25f Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Sat, 13 Oct 2012 16:24:19 +0300 +Subject: [PATCH] da8xx: Add standard panel definition + +Add standard panel definition that can work for the beaglebone +DVI cape. +--- + drivers/video/da8xx-fb.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c +index 866d804..4462d9e 100644 +--- a/drivers/video/da8xx-fb.c ++++ b/drivers/video/da8xx-fb.c +@@ -270,6 +270,20 @@ static struct da8xx_panel known_lcd_panels[] = { + .pxl_clk = 7833600, + .invert_pxl_clk = 0, + }, ++ [3] = { ++ /* 1024 x 768 @ 60 Hz Reduced blanking VESA CVT 0.79M3-R */ ++ .name = "1024x768@60", ++ .width = 1024, ++ .height = 768, ++ .hfp = 48, ++ .hbp = 80, ++ .hsw = 32, ++ .vfp = 3, ++ .vbp = 15, ++ .vsw = 4, ++ .pxl_clk = 56000000, ++ .invert_pxl_clk = 0, ++ }, + }; + + /* Enable the Raster Engine of the LCD Controller */ diff --git a/patches/linux-3.7-rc6/0089-da8xx-Add-CDTech_S035Q01-panel-used-by-LCD3-bone-cap.patch b/patches/linux-3.7-rc6/0089-da8xx-Add-CDTech_S035Q01-panel-used-by-LCD3-bone-cap.patch new file mode 100644 index 0000000..5bff28d --- /dev/null +++ b/patches/linux-3.7-rc6/0089-da8xx-Add-CDTech_S035Q01-panel-used-by-LCD3-bone-cap.patch @@ -0,0 +1,34 @@ +From efa286cb8ea36c5c01aaa632449690528aefcfe9 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Wed, 17 Oct 2012 15:43:55 +0300 +Subject: [PATCH] da8xx: Add CDTech_S035Q01 panel (used by LCD3 bone cape) + +--- + drivers/video/da8xx-fb.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c +index 4462d9e..873789b 100644 +--- a/drivers/video/da8xx-fb.c ++++ b/drivers/video/da8xx-fb.c +@@ -284,6 +284,20 @@ static struct da8xx_panel known_lcd_panels[] = { + .pxl_clk = 56000000, + .invert_pxl_clk = 0, + }, ++ [4] = { ++ /* CDTech S035Q01 */ ++ .name = "CDTech_S035Q01", ++ .width = 320, ++ .height = 240, ++ .hfp = 58, ++ .hbp = 21, ++ .hsw = 47, ++ .vfp = 23, ++ .vbp = 11, ++ .vsw = 2, ++ .pxl_clk = 8000000, ++ .invert_pxl_clk = 0, ++ }, + }; + + /* Enable the Raster Engine of the LCD Controller */ diff --git a/patches/linux-3.7-rc6/0090-da8xx-fb-add-panel-definition-for-beaglebone-LCD7-ca.patch b/patches/linux-3.7-rc6/0090-da8xx-fb-add-panel-definition-for-beaglebone-LCD7-ca.patch new file mode 100644 index 0000000..463ea9a --- /dev/null +++ b/patches/linux-3.7-rc6/0090-da8xx-fb-add-panel-definition-for-beaglebone-LCD7-ca.patch @@ -0,0 +1,35 @@ +From 84ee386766bf356bfdb5adddeb17de5ffc2f948c Mon Sep 17 00:00:00 2001 +From: Koen Kooi <koen@dominion.thruhere.net> +Date: Wed, 17 Oct 2012 11:32:24 +0200 +Subject: [PATCH] da8xx-fb: add panel definition for beaglebone LCD7 cape + +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + drivers/video/da8xx-fb.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c +index 873789b..6d98184 100644 +--- a/drivers/video/da8xx-fb.c ++++ b/drivers/video/da8xx-fb.c +@@ -298,6 +298,20 @@ static struct da8xx_panel known_lcd_panels[] = { + .pxl_clk = 8000000, + .invert_pxl_clk = 0, + }, ++ /* ThreeFive S9700RTWV35TR */ ++ [5] = { ++ .name = "TFC_S9700RTWV35TR_01B", ++ .width = 800, ++ .height = 480, ++ .hfp = 39, ++ .hbp = 39, ++ .hsw = 47, ++ .vfp = 13, ++ .vbp = 29, ++ .vsw = 2, ++ .pxl_clk = 30000000, ++ .invert_pxl_clk = 0, ++ }, + }; + + /* Enable the Raster Engine of the LCD Controller */ diff --git a/patches/linux-3.7-rc6/0092-mmc-omap_hsmmc-Enable-HSPE-bit-for-high-speed-cards.patch b/patches/linux-3.7-rc6/0092-mmc-omap_hsmmc-Enable-HSPE-bit-for-high-speed-cards.patch new file mode 100644 index 0000000..92007c3 --- /dev/null +++ b/patches/linux-3.7-rc6/0092-mmc-omap_hsmmc-Enable-HSPE-bit-for-high-speed-cards.patch @@ -0,0 +1,117 @@ +From 8f6c8615eb09d567eef77036e0d378b65b67ae40 Mon Sep 17 00:00:00 2001 +From: "Hebbar, Gururaja" <gururaja.hebbar@ti.com> +Date: Tue, 4 Sep 2012 13:09:11 +0000 +Subject: [PATCH] mmc: omap_hsmmc: Enable HSPE bit for high speed cards + +HSMMC IP on AM33xx need a special setting to handle High-speed cards. +Other platforms like TI81xx, OMAP4 may need this as-well. This depends +on the HSMMC IP timing closure done for the high speed cards. + +>From AM335x TRM (SPRUH73F - 18.3.12 Output Signals Generation) + +The MMC/SD/SDIO output signals can be driven on either falling edge or +rising edge depending on the SD_HCTL[2] HSPE bit. This feature allows +to reach better timing performance, and thus to increase data transfer +frequency. + +There are few pre-requisites for enabling the HSPE bit +- Controller should support High-Speed-Enable Bit and +- Controller should not be using DDR Mode and +- Controller should advertise that it supports High Speed in + capabilities register and +- MMC/SD clock coming out of controller > 25MHz + +Signed-off-by: Hebbar, Gururaja <gururaja.hebbar@ti.com> +--- + arch/arm/plat-omap/include/plat/mmc.h | 1 + + drivers/mmc/host/omap_hsmmc.c | 30 +++++++++++++++++++++++++++++- + 2 files changed, 30 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h +index 8b4e4f2..346af5b 100644 +--- a/arch/arm/plat-omap/include/plat/mmc.h ++++ b/arch/arm/plat-omap/include/plat/mmc.h +@@ -126,6 +126,7 @@ struct omap_mmc_platform_data { + /* we can put the features above into this variable */ + #define HSMMC_HAS_PBIAS (1 << 0) + #define HSMMC_HAS_UPDATED_RESET (1 << 1) ++#define HSMMC_HAS_HSPE_SUPPORT (1 << 2) + unsigned features; + + int switch_pin; /* gpio (card detect) */ +diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c +index 4fe62b0..897b718 100644 +--- a/drivers/mmc/host/omap_hsmmc.c ++++ b/drivers/mmc/host/omap_hsmmc.c +@@ -62,6 +62,7 @@ + + #define VS18 (1 << 26) + #define VS30 (1 << 25) ++#define HSS (1 << 21) + #define SDVS18 (0x5 << 9) + #define SDVS30 (0x6 << 9) + #define SDVS33 (0x7 << 9) +@@ -89,6 +90,7 @@ + #define MSBS (1 << 5) + #define BCE (1 << 1) + #define FOUR_BIT (1 << 1) ++#define HSPE (1 << 2) + #define DDR (1 << 19) + #define DW8 (1 << 5) + #define CC 0x1 +@@ -494,6 +496,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) + struct mmc_ios *ios = &host->mmc->ios; + unsigned long regval; + unsigned long timeout; ++ unsigned long clkdiv; + + dev_vdbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock); + +@@ -501,7 +504,8 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) + + regval = OMAP_HSMMC_READ(host->base, SYSCTL); + regval = regval & ~(CLKD_MASK | DTO_MASK); +- regval = regval | (calc_divisor(host, ios) << 6) | (DTO << 16); ++ clkdiv = calc_divisor(host, ios); ++ regval = regval | (clkdiv << 6) | (DTO << 16); + OMAP_HSMMC_WRITE(host->base, SYSCTL, regval); + OMAP_HSMMC_WRITE(host->base, SYSCTL, + OMAP_HSMMC_READ(host->base, SYSCTL) | ICE); +@@ -512,6 +516,27 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) + && time_before(jiffies, timeout)) + cpu_relax(); + ++ /* ++ * Enable High-Speed Support ++ * Pre-Requisites ++ * - Controller should support High-Speed-Enable Bit ++ * - Controller should not be using DDR Mode ++ * - Controller should advertise that it supports High Speed ++ * in capabilities register ++ * - MMC/SD clock coming out of controller > 25MHz ++ */ ++ if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) && ++ (ios->timing != MMC_TIMING_UHS_DDR50) && ++ ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) { ++ regval = OMAP_HSMMC_READ(host->base, HCTL); ++ if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000) ++ regval |= HSPE; ++ else ++ regval &= ~HSPE; ++ ++ OMAP_HSMMC_WRITE(host->base, HCTL, regval); ++ } ++ + omap_hsmmc_start_clock(host); + } + +@@ -1705,6 +1730,9 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) + if (of_find_property(np, "ti,needs-special-reset", NULL)) + pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET; + ++ if (of_find_property(np, "ti,needs-special-hs-handling", NULL)) ++ pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT; ++ + return pdata; + } + #else diff --git a/patches/linux-3.7-rc6/0093-am33xx.dtsi-enable-MMC-HSPE-bit-for-all-3-controller.patch b/patches/linux-3.7-rc6/0093-am33xx.dtsi-enable-MMC-HSPE-bit-for-all-3-controller.patch new file mode 100644 index 0000000..dd416dd --- /dev/null +++ b/patches/linux-3.7-rc6/0093-am33xx.dtsi-enable-MMC-HSPE-bit-for-all-3-controller.patch @@ -0,0 +1,38 @@ +From 6a28b2af338fb9b5800829474e26bcbc40005b1a Mon Sep 17 00:00:00 2001 +From: Koen Kooi <koen@dominion.thruhere.net> +Date: Thu, 18 Oct 2012 10:11:48 +0200 +Subject: [PATCH] am33xx.dtsi: enable MMC HSPE bit for all 3 controllers + +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/boot/dts/am33xx.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi +index 9bb71cb..8bddc9c 100644 +--- a/arch/arm/boot/dts/am33xx.dtsi ++++ b/arch/arm/boot/dts/am33xx.dtsi +@@ -263,6 +263,7 @@ + ti,hwmods = "mmc1"; + ti,dual-volt; + ti,needs-special-reset; ++ ti,needs-special-hs-handling; + dmas = <&edma 24 + &edma 25>; + dma-names = "tx", "rx"; +@@ -272,6 +273,7 @@ + compatible = "ti,omap3-hsmmc"; + ti,hwmods = "mmc2"; + ti,needs-special-reset; ++ ti,needs-special-hs-handling; + dmas = <&edma 2 + &edma 3>; + dma-names = "tx", "rx"; +@@ -282,6 +284,7 @@ + compatible = "ti,omap3-hsmmc"; + ti,hwmods = "mmc3"; + ti,needs-special-reset; ++ ti,needs-special-hs-handling; + status = "disabled"; + }; + diff --git a/patches/linux-3.7-rc6/0094-omap-hsmmc-Correct-usage-of-of_find_node_by_name.patch b/patches/linux-3.7-rc6/0094-omap-hsmmc-Correct-usage-of-of_find_node_by_name.patch new file mode 100644 index 0000000..71658ad --- /dev/null +++ b/patches/linux-3.7-rc6/0094-omap-hsmmc-Correct-usage-of-of_find_node_by_name.patch @@ -0,0 +1,23 @@ +From 21e193d74c69102be68cbc76baf581abffcaef2a Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Fri, 26 Oct 2012 15:48:00 +0300 +Subject: [PATCH] omap-hsmmc: Correct usage of of_find_node_by_name + +of_find_node_by_name expect to have the parent node reference taken. +--- + drivers/mmc/host/omap_hsmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c +index 897b718..7a1283c 100644 +--- a/drivers/mmc/host/omap_hsmmc.c ++++ b/drivers/mmc/host/omap_hsmmc.c +@@ -1864,7 +1864,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) + /* Eventually we should get our max_segs limitation for EDMA by + * querying the dmaengine API */ + if (pdev->dev.of_node) { +- struct device_node *parent = pdev->dev.of_node->parent; ++ struct device_node *parent = of_node_get(pdev->dev.of_node->parent); + struct device_node *node; + node = of_find_node_by_name(parent, "edma"); + if (node) diff --git a/patches/linux-3.7-rc6/0096-ARM-AM33XX-hwmod-Remove-wrong-INIT_NO_RESET-IDLE-fla.patch b/patches/linux-3.7-rc6/0096-ARM-AM33XX-hwmod-Remove-wrong-INIT_NO_RESET-IDLE-fla.patch new file mode 100644 index 0000000..66399f4 --- /dev/null +++ b/patches/linux-3.7-rc6/0096-ARM-AM33XX-hwmod-Remove-wrong-INIT_NO_RESET-IDLE-fla.patch @@ -0,0 +1,25 @@ +From 0e2a3d8d4c5c17660c8e3410826c4d9f7f222968 Mon Sep 17 00:00:00 2001 +From: Vaibhav Hiremath <hvaibhav@ti.com> +Date: Fri, 19 Oct 2012 02:01:39 +0530 +Subject: [PATCH] ARM: AM33XX: hwmod: Remove wrong INIT_NO_RESET/IDLE flags + from cpgmac entry + +Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com> +--- + arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +index 2a5032f..76531f9 100644 +--- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c ++++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +@@ -681,8 +681,7 @@ static struct omap_hwmod am33xx_cpgmac0_hwmod = { + .modulemode = MODULEMODE_SWCTRL, + }, + }, +- .flags = (HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY | +- HWMOD_INIT_NO_RESET | HWMOD_INIT_NO_IDLE), ++ .flags = (HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY), + }; + + /* diff --git a/patches/linux-3.7-rc6/0098-f2fs-add-document.patch b/patches/linux-3.7-rc6/0098-f2fs-add-document.patch new file mode 100644 index 0000000..367300f --- /dev/null +++ b/patches/linux-3.7-rc6/0098-f2fs-add-document.patch @@ -0,0 +1,438 @@ +From c7823b127b80e70f1eabc0af8ddcab7640cc9d41 Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:25:11 +0000 +Subject: [PATCH] f2fs: add document + +This adds a document describing the mount options, proc entries, usage, and +design of Flash-Friendly File System, namely F2FS. + +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + Documentation/filesystems/00-INDEX | 2 + + Documentation/filesystems/f2fs.txt | 404 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 406 insertions(+) + create mode 100644 Documentation/filesystems/f2fs.txt + +diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX +index 8c624a1..ce5fd46 100644 +--- a/Documentation/filesystems/00-INDEX ++++ b/Documentation/filesystems/00-INDEX +@@ -48,6 +48,8 @@ ext4.txt + - info, mount options and specifications for the Ext4 filesystem. + files.txt + - info on file management in the Linux kernel. ++f2fs.txt ++ - info and mount options for the F2FS filesystem. + fuse.txt + - info on the Filesystem in User SpacE including mount options. + gfs2.txt +diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt +new file mode 100644 +index 0000000..f2b4fde +--- /dev/null ++++ b/Documentation/filesystems/f2fs.txt +@@ -0,0 +1,404 @@ ++================================================================================ ++WHAT IS Flash-Friendly File System (F2FS)? ++================================================================================ ++ ++NAND flash memory-based storage devices, such as SSD, eMMC, and SD cards, have ++been widely being used for storage ranging from mobile to server systems. Since ++they are known to have different characteristics from the conventional rotating ++disks, a file system, an upper layer to the storage device, should adapt to the ++changes from the sketch in the design level. ++ ++F2FS is a file system exploiting NAND flash memory-based storage devices, which ++is based on Log-structured File System (LFS). The design has been focused on ++addressing the fundamental issues in LFS, which are snowball effect of wandering ++tree and high cleaning overhead. ++ ++Since a NAND flash memory-based storage device shows different characteristic ++according to its internal geometry or flash memory management scheme, namely FTL, ++F2FS and its tools support various parameters not only for configuring on-disk ++layout, but also for selecting allocation and cleaning algorithms. ++ ++The file system formatting tool, "mkfs.f2fs", is available from the following ++download page: http://sourceforge.net/projects/f2fs-tools/ ++ ++================================================================================ ++BACKGROUND AND DESIGN ISSUES ++================================================================================ ++ ++Log-structured File System (LFS) ++-------------------------------- ++"A log-structured file system writes all modifications to disk sequentially in ++a log-like structure, thereby speeding up both file writing and crash recovery. ++The log is the only structure on disk; it contains indexing information so that ++files can be read back from the log efficiently. In order to maintain large free ++areas on disk for fast writing, we divide the log into segments and use a ++segment cleaner to compress the live information from heavily fragmented ++segments." from Rosenblum, M. and Ousterhout, J. K., 1992, "The design and ++implementation of a log-structured file system", ACM Trans. Computer Systems ++10, 1, 26–52. ++ ++Wandering Tree Problem ++---------------------- ++In LFS, when a file data is updated and written to the end of log, its direct ++pointer block is updated due to the changed location. Then the indirect pointer ++block is also updated due to the direct pointer block update. In this manner, ++the upper index structures such as inode, inode map, and checkpoint block are ++also updated recursively. This problem is called as wandering tree problem [1], ++and in order to enhance the performance, it should eliminate or relax the update ++propagation as much as possible. ++ ++[1] Bityutskiy, A. 2005. JFFS3 design issues. http://www.linux-mtd.infradead.org/ ++ ++Cleaning Overhead ++----------------- ++Since LFS is based on out-of-place writes, it produces so many obsolete blocks ++scattered across the whole storage. In order to serve new empty log space, it ++needs to reclaim these obsolete blocks seamlessly to users. This job is called ++as a cleaning process. ++ ++The process consists of three operations as follows. ++1. A victim segment is selected through referencing segment usage table. ++2. It loads parent index structures of all the data in the victim identified by ++ segment summary blocks. ++3. It checks the cross-reference between the data and its parent index structure. ++4. It moves valid data selectively. ++ ++This cleaning job may cause unexpected long delays, so the most important goal ++is to hide the latencies to users. And also definitely, it should reduce the ++amount of valid data to be moved, and move them quickly as well. ++ ++================================================================================ ++KEY FEATURES ++================================================================================ ++ ++Flash Awareness ++--------------- ++- Enlarge the random write area for better performance, but provide the high ++ spatial locality ++- Align FS data structures to the operational units in FTL as best efforts ++ ++Wandering Tree Problem ++---------------------- ++- Use a term, “node”, that represents inodes as well as various pointer blocks ++- Introduce Node Address Table (NAT) containing the locations of all the “node” ++ blocks; this will cut off the update propagation. ++ ++Cleaning Overhead ++----------------- ++- Support a background cleaning process ++- Support greedy and cost-benefit algorithms for victim selection policies ++- Support multi-head logs for static/dynamic hot and cold data separation ++- Introduce adaptive logging for efficient block allocation ++ ++================================================================================ ++MOUNT OPTIONS ++================================================================================ ++ ++background_gc_off Turn off cleaning operations, namely garbage collection, ++ triggered in background when I/O subsystem is idle. ++disable_roll_forward Disable the roll-forward recovery routine ++discard Issue discard/TRIM commands when a segment is cleaned. ++no_heap Disable heap-style segment allocation which finds free ++ segments for data from the beginning of main area, while ++ for node from the end of main area. ++nouser_xattr Disable Extended User Attributes. Note: xattr is enabled ++ by default if CONFIG_F2FS_FS_XATTR is selected. ++noacl Disable POSIX Access Control List. Note: acl is enabled ++ by default if CONFIG_F2FS_FS_POSIX_ACL is selected. ++active_logs=%u Support configuring the number of active logs. In the ++ current design, f2fs supports only 2, 4, and 6 logs. ++ Default number is 6. ++disable_ext_identify Disable the extension list configured by mkfs, so f2fs ++ does not aware of cold files such as media files. ++ ++================================================================================ ++PROC ENTRIES ++================================================================================ ++ ++/proc/fs/f2fs/ contains information about partitions mounted as f2fs. For each ++partition, a corresponding directory, named as its device name, is provided with ++the following proc entries. ++ ++- f2fs_stat major file system information managed by f2fs currently ++- f2fs_sit_stat average utilization information of the whole segments ++- f2fs_mem_stat current memory footprint consumed by f2fs ++ ++e.g., in /proc/fs/f2fs/sdb1/ ++ ++================================================================================ ++USAGE ++================================================================================ ++ ++1. Download userland tools ++ ++2. Insmod f2fs.ko module: ++ # insmod f2fs.ko ++ ++3. Check the directory trying to mount ++ # mkdir /mnt/f2fs ++ ++4. Format the block device, and then mount as f2fs ++ # mkfs.f2fs -l label /dev/block_device ++ # mount -t f2fs /dev/block_device /mnt/f2fs ++ ++Mount options ++------------- ++-l [label] : Give a volume label, up to 256 unicode name. ++-a [0 or 1] : Split start location of each area for heap-based allocation. ++ 1 is set by default, which performs this. ++-o [int] : Set overprovision ratio in percent over volume size. ++ 5 is set by default. ++-s [int] : Set the number of segments per section. ++ 1 is set by default. ++-z [int] : Set the number of sections per zone. ++ 1 is set by default. ++-e [str] : Set basic extension list. e.g. "mp3,gif,mov" ++ ++================================================================================ ++DESIGN ++================================================================================ ++ ++On-disk Layout ++-------------- ++ ++F2FS divides the whole volume into a number of segments, each of which is 2MB in ++size by default. A section is composed of consecutive segments, and a zone ++consists of a set of sections. ++ ++F2FS maintains logically six log areas. Except SB, all the log areas are managed ++in a unit of multiple segments. SB is located at the beginning of the partition, ++and there exist two superblocks to avoid file system crash. Other file system ++metadata such as CP, NAT, SIT, and SSA are located in the front part of the ++volume. Main area contains file and directory data including their indices. ++ ++Each area manages the following contents. ++- CP File system information, bitmaps for valid NAT/SIT sets, orphan ++ inode lists, and summary entries of current active segments. ++- NAT Block address table for all the node blocks stored in Main area. ++- SIT Segment information such as valid block count and bitmap for the ++ validity of all the blocks. ++- SSA Summary entries which contains the owner information of all the ++ data and node blocks stored in Main area. ++- Main Node and data blocks. ++ ++In order to avoid misalignment between file system and flash-based storage, F2FS ++aligns the start block address of CP with the segment size. Also, it aligns the ++start block address of Main area with the zone size by reserving some segments ++in SSA area. ++ ++ align with the zone size <-| ++ |-> align with the segment size ++ _________________________________________________________________________ ++ | | | Node | Segment | Segment | | ++ | Superblock | Checkpoint | Address | Info. | Summary | Main | ++ | (SB) | (CP) | Table (NAT) | Table (SIT) | Area (SSA) | | ++ |____________|_____2______|______N______|______N______|______N_____|__N___| ++ . . ++ . . ++ . . ++ ._________________________________________. ++ |_Segment_|_..._|_Segment_|_..._|_Segment_| ++ . . ++ ._________._________ ++ |_section_|__...__|_ ++ . . ++ .________. ++ |__zone__| ++ ++ ++File System Metadata Structure ++------------------------------ ++ ++F2FS adopts the checkpointing scheme to maintain file system consistency. At ++mount time, F2FS first tries to find the last valid checkpoint data by scanning ++CP area. In order to reduce the scanning time, F2FS uses only two copies of CP. ++One of them always indicates the last valid data, which is called as shadow copy ++mechanism. In addition to CP, NAT and SIT also adopt the shadow copy mechanism. ++ ++For file system consistency, each CP points to which NAT and SIT copies are ++valid, as shown as below. ++ ++ +--------+----------+---------+ ++ | CP | NAT | SIT | ++ +--------+----------+---------+ ++ . . . . ++ . . . . ++ . . . . ++ +-------+-------+--------+--------+--------+--------+ ++ | CP #0 | CP #1 | NAT #0 | NAT #1 | SIT #0 | SIT #1 | ++ +-------+-------+--------+--------+--------+--------+ ++ | ^ ^ ++ | | | ++ `----------------------------------------' ++ ++Index Structure ++--------------- ++ ++The key data structure to manage the data locations is a "node". Similar to ++traditional file structures, F2FS has three types of node: inode, direct node, ++indirect node. F2FS assigns 4KB to an inode block which contains 929 data block ++indices, two direct node pointers, two indirect node pointers, and one double ++indirect node pointer as described below. One direct node block contains 1018 ++data blocks, and one indirect node block contains also 1018 node blocks. Thus, ++one inode block (i.e., a file) covers: ++ ++ 4KB * (927 + 2 * 1018 + 2 * 1018 * 1018 + 1018 * 1018 * 1018) := 3.94TB. ++ ++ Inode block (4KB) ++ |- data (927) ++ |- direct node (2) ++ | `- data (1018) ++ |- indirect node (2) ++ | `- direct node (1018) ++ | `- data (1018) ++ `- double indirect node (1) ++ `- indirect node (1018) ++ `- direct node (1018) ++ `- data (1018) ++ ++Note that, all the node blocks are mapped by NAT which means the location of ++each node is translated by the NAT table. In the consideration of the wandering ++tree problem, F2FS is able to cut off the propagation of node updates caused by ++leaf data writes. ++ ++Directory Structure ++------------------- ++ ++A directory entry occupies 11 bytes, which consists of the following attributes. ++ ++- hash hash value of the file name ++- ino inode number ++- len the length of file name ++- type file type such as directory, symlink, etc ++ ++A dentry block consists of 214 dentry slots and file names. Therein a bitmap is ++used to represent whether each dentry is valid or not. A dentry block occupies ++4KB with the following composition. ++ ++ Dentry Block(4 K) = bitmap (27 bytes) + reserved (3 bytes) + ++ dentries(11 * 214 bytes) + file name (8 * 214 bytes) ++ ++ [Bucket] ++ +--------------------------------+ ++ |dentry block 1 | dentry block 2 | ++ +--------------------------------+ ++ . . ++ . . ++ . [Dentry Block Structure: 4KB] . ++ +--------+----------+----------+------------+ ++ | bitmap | reserved | dentries | file names | ++ +--------+----------+----------+------------+ ++ [Dentry Block: 4KB] . . ++ . . ++ . . ++ +------+------+-----+------+ ++ | hash | ino | len | type | ++ +------+------+-----+------+ ++ [Dentry Structure: 11 bytes] ++ ++F2FS implements multi-level hash tables for directory structure. Each level has ++a hash table with dedicated number of hash buckets as shown below. Note that ++"A(2B)" means a bucket includes 2 data blocks. ++ ++---------------------- ++A : bucket ++B : block ++N : MAX_DIR_HASH_DEPTH ++---------------------- ++ ++level #0 | A(2B) ++ | ++level #1 | A(2B) - A(2B) ++ | ++level #2 | A(2B) - A(2B) - A(2B) - A(2B) ++ . | . . . . ++level #N/2 | A(2B) - A(2B) - A(2B) - A(2B) - A(2B) - ... - A(2B) ++ . | . . . . ++level #N | A(4B) - A(4B) - A(4B) - A(4B) - A(4B) - ... - A(4B) ++ ++The number of blocks and buckets are determined by, ++ ++ ,- 2, if n < MAX_DIR_HASH_DEPTH / 2, ++ # of blocks in level #n = | ++ `- 4, Otherwise ++ ++ ,- 2^n, if n < MAX_DIR_HASH_DEPTH / 2, ++ # of buckets in level #n = | ++ `- 2^((MAX_DIR_HASH_DEPTH / 2) - 1), Otherwise ++ ++When F2FS finds a file name in a directory, at first a hash value of the file ++name is calculated. Then, F2FS scans the hash table in level #0 to find the ++dentry consisting of the file name and its inode number. If not found, F2FS ++scans the next hash table in level #1. In this way, F2FS scans hash tables in ++each levels incrementally from 1 to N. In each levels F2FS needs to scan only ++one bucket determined by the following equation, which shows O(log(# of files)) ++complexity. ++ ++ bucket number to scan in level #n = (hash value) % (# of buckets in level #n) ++ ++In the case of file creation, F2FS finds empty consecutive slots that cover the ++file name. F2FS searches the empty slots in the hash tables of whole levels from ++1 to N in the same way as the lookup operation. ++ ++The following figure shows an example of two cases holding children. ++ --------------> Dir <-------------- ++ | | ++ child child ++ ++ child - child [hole] - child ++ ++ child - child - child [hole] - [hole] - child ++ ++ Case 1: Case 2: ++ Number of children = 6, Number of children = 3, ++ File size = 7 File size = 7 ++ ++Default Block Allocation ++------------------------ ++ ++At runtime, F2FS manages six active logs inside "Main" area: Hot/Warm/Cold node ++and Hot/Warm/Cold data. ++ ++- Hot node contains direct node blocks of directories. ++- Warm node contains direct node blocks except hot node blocks. ++- Cold node contains indirect node blocks ++- Hot data contains dentry blocks ++- Warm data contains data blocks except hot and cold data blocks ++- Cold data contains multimedia data or migrated data blocks ++ ++LFS has two schemes for free space management: threaded log and copy-and-compac- ++tion. The copy-and-compaction scheme which is known as cleaning, is well-suited ++for devices showing very good sequential write performance, since free segments ++are served all the time for writing new data. However, it suffers from cleaning ++overhead under high utilization. Contrarily, the threaded log scheme suffers ++from random writes, but no cleaning process is needed. F2FS adopts a hybrid ++scheme where the copy-and-compaction scheme is adopted by default, but the ++policy is dynamically changed to the threaded log scheme according to the file ++system status. ++ ++In order to align F2FS with underlying flash-based storage, F2FS allocates a ++segment in a unit of section. F2FS expects that the section size would be the ++same as the unit size of garbage collection in FTL. Furthermore, with respect ++to the mapping granularity in FTL, F2FS allocates each section of the active ++logs from different zones as much as possible, since FTL can write the data in ++the active logs into one allocation unit according to its mapping granularity. ++ ++Cleaning process ++---------------- ++ ++F2FS does cleaning both on demand and in the background. On-demand cleaning is ++triggered when there are not enough free segments to serve VFS calls. Background ++cleaner is operated by a kernel thread, and triggers the cleaning job when the ++system is idle. ++ ++F2FS supports two victim selection policies: greedy and cost-benefit algorithms. ++In the greedy algorithm, F2FS selects a victim segment having the smallest number ++of valid blocks. In the cost-benefit algorithm, F2FS selects a victim segment ++according to the segment age and the number of valid blocks in order to address ++log block thrashing problem in the greedy algorithm. F2FS adopts the greedy ++algorithm for on-demand cleaner, while background cleaner adopts cost-benefit ++algorithm. ++ ++In order to identify whether the data in the victim segment are valid or not, ++F2FS manages a bitmap. Each bit represents the validity of a block, and the ++bitmap is composed of a bit stream covering whole blocks in main area. diff --git a/patches/linux-3.7-rc6/0099-f2fs-add-on-disk-layout.patch b/patches/linux-3.7-rc6/0099-f2fs-add-on-disk-layout.patch new file mode 100644 index 0000000..be4892c --- /dev/null +++ b/patches/linux-3.7-rc6/0099-f2fs-add-on-disk-layout.patch @@ -0,0 +1,383 @@ +From 902033dcdb656694672091702bc88f5020b69443 Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:26:00 +0000 +Subject: [PATCH] f2fs: add on-disk layout + +This adds a header file describing the on-disk layout of f2fs. + +Signed-off-by: Changman Lee <cm224.lee@samsung.com> +Signed-off-by: Chul Lee <chur.lee@samsung.com> +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + include/linux/f2fs_fs.h | 362 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 362 insertions(+) + create mode 100644 include/linux/f2fs_fs.h + +diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h +new file mode 100644 +index 0000000..bd9c217 +--- /dev/null ++++ b/include/linux/f2fs_fs.h +@@ -0,0 +1,362 @@ ++/** ++ * include/linux/f2fs_fs.h ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef _LINUX_F2FS_FS_H ++#define _LINUX_F2FS_FS_H ++ ++#include <linux/pagemap.h> ++#include <linux/types.h> ++ ++#define F2FS_SUPER_MAGIC 0xF2F52010 ++#define F2FS_SUPER_OFFSET 0 /* start sector # for sb */ ++#define F2FS_BLKSIZE 4096 ++#define F2FS_MAX_EXTENSION 64 ++ ++#define NULL_ADDR 0x0U ++#define NEW_ADDR -1U ++ ++#define F2FS_ROOT_INO(sbi) (sbi->root_ino_num) ++#define F2FS_NODE_INO(sbi) (sbi->node_ino_num) ++#define F2FS_META_INO(sbi) (sbi->meta_ino_num) ++ ++#define GFP_F2FS_MOVABLE (__GFP_WAIT | __GFP_IO | __GFP_ZERO) ++ ++#define MAX_ACTIVE_LOGS 16 ++#define MAX_ACTIVE_NODE_LOGS 8 ++#define MAX_ACTIVE_DATA_LOGS 8 ++ ++/* ++ * For superblock ++ */ ++struct f2fs_super_block { ++ __le32 magic; /* Magic Number */ ++ __le16 major_ver; /* Major Version */ ++ __le16 minor_ver; /* Minor Version */ ++ __le32 log_sectorsize; /* log2 (Sector size in bytes) */ ++ __le32 log_sectors_per_block; /* log2 (Number of sectors per block */ ++ __le32 log_blocksize; /* log2 (Block size in bytes) */ ++ __le32 log_blocks_per_seg; /* log2 (Number of blocks per segment) */ ++ __le32 segs_per_sec; /* Number of segments per section */ ++ __le32 secs_per_zone; /* Number of sections per zone */ ++ __le32 checksum_offset; /* Checksum position in this super block */ ++ __le64 block_count; /* Total number of blocks */ ++ __le32 section_count; /* Total number of sections */ ++ __le32 segment_count; /* Total number of segments */ ++ __le32 segment_count_ckpt; /* Total number of segments ++ in Checkpoint area */ ++ __le32 segment_count_sit; /* Total number of segments ++ in Segment information table */ ++ __le32 segment_count_nat; /* Total number of segments ++ in Node address table */ ++ /*Total number of segments in Segment summary area */ ++ __le32 segment_count_ssa; ++ /* Total number of segments in Main area */ ++ __le32 segment_count_main; ++ __le32 failure_safe_block_distance; ++ __le32 segment0_blkaddr; /* Start block address of Segment 0 */ ++ __le32 start_segment_checkpoint; /* Start block address of ckpt */ ++ __le32 sit_blkaddr; /* Start block address of SIT */ ++ __le32 nat_blkaddr; /* Start block address of NAT */ ++ __le32 ssa_blkaddr; /* Start block address of SSA */ ++ __le32 main_blkaddr; /* Start block address of Main area */ ++ __le32 root_ino; /* Root directory inode number */ ++ __le32 node_ino; /* node inode number */ ++ __le32 meta_ino; /* meta inode number */ ++ __le32 volume_serial_number; /* VSN is optional field */ ++ __le16 volume_name[512]; /* Volume Name */ ++ __le32 extension_count; ++ __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */ ++} __packed; ++ ++/* ++ * For checkpoint ++ */ ++struct f2fs_checkpoint { ++ __le64 checkpoint_ver; /* Checkpoint block version number */ ++ __le64 user_block_count; /* # of user blocks */ ++ __le64 valid_block_count; /* # of valid blocks in Main area */ ++ __le32 rsvd_segment_count; /* # of reserved segments for gc */ ++ __le32 overprov_segment_count; /* # of overprovision segments */ ++ __le32 free_segment_count; /* # of free segments in Main area */ ++ ++ /* information of current node segments */ ++ __le32 cur_node_segno[MAX_ACTIVE_NODE_LOGS]; ++ __le16 cur_node_blkoff[MAX_ACTIVE_NODE_LOGS]; ++ __le16 nat_upd_blkoff[MAX_ACTIVE_NODE_LOGS]; ++ /* information of current data segments */ ++ __le32 cur_data_segno[MAX_ACTIVE_DATA_LOGS]; ++ __le16 cur_data_blkoff[MAX_ACTIVE_DATA_LOGS]; ++ __le32 ckpt_flags; /* Flags : umount and journal_present */ ++ __le32 cp_pack_total_block_count; ++ __le32 cp_pack_start_sum; /* start block number of data summary */ ++ __le32 valid_node_count; /* Total number of valid nodes */ ++ __le32 valid_inode_count; /* Total number of valid inodes */ ++ __le32 next_free_nid; /* Next free node number */ ++ __le32 sit_ver_bitmap_bytesize; /* Default value 64 */ ++ __le32 nat_ver_bitmap_bytesize; /* Default value 256 */ ++ __le32 checksum_offset; /* Checksum position ++ in this checkpoint block */ ++ __le64 elapsed_time; /* elapsed time while partition ++ is mounted */ ++ /* allocation type of current segment */ ++ unsigned char alloc_type[MAX_ACTIVE_LOGS]; ++ ++ /* SIT and NAT version bitmap */ ++ unsigned char sit_nat_version_bitmap[1]; ++} __packed; ++ ++/* ++ * For orphan inode management ++ */ ++#define F2FS_ORPHANS_PER_BLOCK 1020 ++ ++struct f2fs_orphan_block { ++ __le32 ino[F2FS_ORPHANS_PER_BLOCK]; /* inode numbers */ ++ __le32 reserved; ++ __le16 blk_addr; /* block index in current CP */ ++ __le16 blk_count; /* Number of orphan inode blocks in CP */ ++ __le32 entry_count; /* Total number of orphan nodes in current CP */ ++ __le32 check_sum; /* CRC32 for orphan inode block */ ++} __packed; ++ ++/* ++ * For NODE structure ++ */ ++struct f2fs_extent { ++ __le32 fofs; ++ __le32 blk_addr; ++ __le32 len; ++} __packed; ++ ++#define F2FS_MAX_NAME_LEN 256 ++#define ADDRS_PER_INODE 927 /* Address Pointers in an Inode */ ++#define ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */ ++#define NIDS_PER_BLOCK 1018 /* Node IDs in an Indirect Block */ ++ ++struct f2fs_inode { ++ __le16 i_mode; /* File mode */ ++ __u8 i_advise; /* File hints */ ++ __u8 i_reserved; /* Reserved */ ++ __le32 i_uid; /* User ID */ ++ __le32 i_gid; /* Group ID */ ++ __le32 i_links; /* Links count */ ++ __le64 i_size; /* File size in bytes */ ++ __le64 i_blocks; /* File size in blocks */ ++ __le64 i_ctime; /* Inode change time */ ++ __le64 i_mtime; /* Modification time */ ++ __le32 i_ctime_nsec; ++ __le32 i_mtime_nsec; ++ __le32 current_depth; ++ __le32 i_xattr_nid; /* nid to save xattr */ ++ __le32 i_flags; /* file attributes */ ++ __le32 i_pino; /* parent inode number */ ++ __le32 i_namelen; /* file name length */ ++ __u8 i_name[F2FS_MAX_NAME_LEN]; /* file name for SPOR */ ++ ++ struct f2fs_extent i_ext; /* caching a largest extent */ ++ ++ __le32 i_addr[ADDRS_PER_INODE]; /* Pointers to data blocks */ ++ ++ __le32 i_nid[5]; /* direct(2), indirect(2), ++ double_indirect(1) node id */ ++} __packed; ++ ++struct direct_node { ++ __le32 addr[ADDRS_PER_BLOCK]; /* array of data block address */ ++} __packed; ++ ++struct indirect_node { ++ __le32 nid[NIDS_PER_BLOCK]; /* array of data block address */ ++} __packed; ++ ++enum { ++ COLD_BIT_SHIFT = 0, ++ FSYNC_BIT_SHIFT, ++ DENT_BIT_SHIFT, ++ OFFSET_BIT_SHIFT ++}; ++ ++struct node_footer { ++ __le32 nid; /* node id */ ++ __le32 ino; /* inode nunmber */ ++ __le32 flag; /* include cold/fsync/dentry marks and offset */ ++ __le64 cp_ver; /* checkpoint version */ ++ __le32 next_blkaddr; /* next node page block address */ ++} __packed; ++ ++struct f2fs_node { ++ union { ++ struct f2fs_inode i; ++ struct direct_node dn; ++ struct indirect_node in; ++ }; ++ struct node_footer footer; ++} __packed; ++ ++/* ++ * For NAT entries ++ */ ++#define NAT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_nat_entry)) ++ ++struct f2fs_nat_entry { ++ __u8 version; ++ __le32 ino; ++ __le32 block_addr; ++} __packed; ++ ++struct f2fs_nat_block { ++ struct f2fs_nat_entry entries[NAT_ENTRY_PER_BLOCK]; ++} __packed; ++ ++/* ++ * For SIT entries ++ */ ++#define SIT_VBLOCK_MAP_SIZE 64 ++#define SIT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_sit_entry)) ++ ++struct f2fs_sit_entry { ++ __le16 vblocks; ++ __u8 valid_map[SIT_VBLOCK_MAP_SIZE]; ++ __le64 mtime; ++} __packed; ++ ++struct f2fs_sit_block { ++ struct f2fs_sit_entry entries[SIT_ENTRY_PER_BLOCK]; ++} __packed; ++ ++/** ++ * For segment summary ++ * ++ * NOTE : For initializing fields, you must use set_summary ++ * ++ * - If data page, nid represents dnode's nid ++ * - If node page, nid represents the node page's nid. ++ * ++ * The ofs_in_node is used by only data page. It represents offset ++ * from node's page's beginning to get a data block address. ++ * ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node) ++ */ ++struct f2fs_summary { ++ __le32 nid; ++ union { ++ __u8 reserved[3]; ++ struct { ++ __u8 version; ++ __le16 ofs_in_node; ++ } __packed; ++ }; ++} __packed; ++ ++struct summary_footer { ++ unsigned char entry_type; ++ __u32 check_sum; ++} __packed; ++ ++#define SUMMARY_SIZE (sizeof(struct f2fs_summary)) ++#define SUM_FOOTER_SIZE (sizeof(struct summary_footer)) ++#define ENTRIES_IN_SUM 512 ++#define SUM_ENTRY_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM) ++#define SUM_JOURNAL_SIZE (PAGE_CACHE_SIZE - SUM_FOOTER_SIZE -\ ++ SUM_ENTRY_SIZE) ++struct nat_journal_entry { ++ __le32 nid; ++ struct f2fs_nat_entry ne; ++} __packed; ++ ++struct sit_journal_entry { ++ __le32 segno; ++ struct f2fs_sit_entry se; ++} __packed; ++ ++#define NAT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\ ++ sizeof(struct nat_journal_entry)) ++#define NAT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\ ++ sizeof(struct nat_journal_entry)) ++#define SIT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\ ++ sizeof(struct sit_journal_entry)) ++#define SIT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\ ++ sizeof(struct sit_journal_entry)) ++enum { ++ NAT_JOURNAL = 0, ++ SIT_JOURNAL ++}; ++ ++struct nat_journal { ++ struct nat_journal_entry entries[NAT_JOURNAL_ENTRIES]; ++ __u8 reserved[NAT_JOURNAL_RESERVED]; ++} __packed; ++ ++struct sit_journal { ++ struct sit_journal_entry entries[SIT_JOURNAL_ENTRIES]; ++ __u8 reserved[SIT_JOURNAL_RESERVED]; ++} __packed; ++ ++struct f2fs_summary_block { ++ struct f2fs_summary entries[ENTRIES_IN_SUM]; ++ union { ++ __le16 n_nats; ++ __le16 n_sits; ++ }; ++ union { ++ struct nat_journal nat_j; ++ struct sit_journal sit_j; ++ }; ++ struct summary_footer footer; ++} __packed; ++ ++/* ++ * For directory operations ++ */ ++#define F2FS_DOT_HASH 0 ++#define F2FS_DDOT_HASH F2FS_DOT_HASH ++#define F2FS_MAX_HASH (~((0x3ULL) << 62)) ++#define F2FS_HASH_COL_BIT ((0x1ULL) << 63) ++ ++typedef __le32 f2fs_hash_t; ++ ++#define F2FS_NAME_LEN 8 ++#define NR_DENTRY_IN_BLOCK 214 /* the number of dentry in a block */ ++#define MAX_DIR_HASH_DEPTH 63 /* MAX level for dir lookup */ ++ ++#define SIZE_OF_DIR_ENTRY 11 /* by byte */ ++#define SIZE_OF_DENTRY_BITMAP ((NR_DENTRY_IN_BLOCK + BITS_PER_BYTE - 1) / \ ++ BITS_PER_BYTE) ++#define SIZE_OF_RESERVED (PAGE_SIZE - ((SIZE_OF_DIR_ENTRY + \ ++ F2FS_NAME_LEN) * \ ++ NR_DENTRY_IN_BLOCK + SIZE_OF_DENTRY_BITMAP)) ++ ++struct f2fs_dir_entry { ++ __le32 hash_code; /* hash code of file name */ ++ __le32 ino; /* node number of inode */ ++ __le16 name_len; /* the size of file name ++ length in unicode characters */ ++ __u8 file_type; ++} __packed; ++ ++struct f2fs_dentry_block { ++ __u8 dentry_bitmap[SIZE_OF_DENTRY_BITMAP]; ++ __u8 reserved[SIZE_OF_RESERVED]; ++ struct f2fs_dir_entry dentry[NR_DENTRY_IN_BLOCK]; ++ __u8 filename[NR_DENTRY_IN_BLOCK][F2FS_NAME_LEN]; ++} __packed; ++ ++enum { ++ F2FS_FT_UNKNOWN, ++ F2FS_FT_REG_FILE, ++ F2FS_FT_DIR, ++ F2FS_FT_CHRDEV, ++ F2FS_FT_BLKDEV, ++ F2FS_FT_FIFO, ++ F2FS_FT_SOCK, ++ F2FS_FT_SYMLINK, ++ F2FS_FT_MAX ++}; ++ ++#endif /* _LINUX_F2FS_FS_H */ diff --git a/patches/linux-3.7-rc6/0100-f2fs-add-superblock-and-major-in-memory-structure.patch b/patches/linux-3.7-rc6/0100-f2fs-add-superblock-and-major-in-memory-structure.patch new file mode 100644 index 0000000..4f978c2 --- /dev/null +++ b/patches/linux-3.7-rc6/0100-f2fs-add-superblock-and-major-in-memory-structure.patch @@ -0,0 +1,1962 @@ +From 3cfaeeaa816257ae02bbd9486355ad02abbc4c08 Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:26:49 +0000 +Subject: [PATCH] f2fs: add superblock and major in-memory structure + +This adds the following major in-memory structures in f2fs. + +- f2fs_sb_info: + contains f2fs-specific information, two special inode pointers for node and + meta address spaces, and orphan inode management. + +- f2fs_inode_info: + contains vfs_inode and other fs-specific information. + +- f2fs_nm_info: + contains node manager information such as NAT entry cache, free nid list, + and NAT page management. + +- f2fs_node_info: + represents a node as node id, inode number, block address, and its version. + +- f2fs_sm_info: + contains segment manager information such as SIT entry cache, free segment + map, current active logs, dirty segment management, and segment utilization. + The specific structures are sit_info, free_segmap_info, dirty_seglist_info, + curseg_info. + +Signed-off-by: Chul Lee <chur.lee@samsung.com> +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/f2fs/f2fs.h | 982 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/f2fs/node.h | 330 ++++++++++++++++++ + fs/f2fs/segment.h | 594 ++++++++++++++++++++++++++++++++ + 3 files changed, 1906 insertions(+) + create mode 100644 fs/f2fs/f2fs.h + create mode 100644 fs/f2fs/node.h + create mode 100644 fs/f2fs/segment.h + +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +new file mode 100644 +index 0000000..bbe2f02 +--- /dev/null ++++ b/fs/f2fs/f2fs.h +@@ -0,0 +1,982 @@ ++/** ++ * fs/f2fs/f2fs.h ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef _LINUX_F2FS_H ++#define _LINUX_F2FS_H ++ ++#include <linux/types.h> ++#include <linux/page-flags.h> ++#include <linux/buffer_head.h> ++#include <linux/version.h> ++#include <linux/slab.h> ++#include <linux/crc32.h> ++ ++/** ++ * For mount options ++ */ ++#define F2FS_MOUNT_BG_GC 0x00000001 ++#define F2FS_MOUNT_DISABLE_ROLL_FORWARD 0x00000002 ++#define F2FS_MOUNT_DISCARD 0x00000004 ++#define F2FS_MOUNT_NOHEAP 0x00000008 ++#define F2FS_MOUNT_XATTR_USER 0x00000010 ++#define F2FS_MOUNT_POSIX_ACL 0x00000020 ++#define F2FS_MOUNT_DISABLE_EXT_IDENTIFY 0x00000040 ++ ++#define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option) ++#define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option) ++#define test_opt(sbi, option) (sbi->mount_opt.opt & F2FS_MOUNT_##option) ++ ++#define ver_after(a, b) (typecheck(unsigned long long, a) && \ ++ typecheck(unsigned long long, b) && \ ++ ((long long)((a) - (b)) > 0)) ++ ++typedef u64 block_t; ++typedef u32 nid_t; ++ ++struct f2fs_mount_info { ++ unsigned int opt; ++}; ++ ++static inline __u32 f2fs_crc32(void *buff, size_t len) ++{ ++ return crc32_le(F2FS_SUPER_MAGIC, buff, len); ++} ++ ++static inline bool f2fs_crc_valid(__u32 blk_crc, void *buff, size_t buff_size) ++{ ++ return f2fs_crc32(buff, buff_size) == blk_crc; ++} ++ ++/** ++ * For checkpoint manager ++ */ ++#define CP_ERROR_FLAG 0x00000008 ++#define CP_COMPACT_SUM_FLAG 0x00000004 ++#define CP_ORPHAN_PRESENT_FLAG 0x00000002 ++#define CP_UMOUNT_FLAG 0x00000001 ++ ++enum { ++ NAT_BITMAP, ++ SIT_BITMAP ++}; ++ ++struct orphan_inode_entry { ++ struct list_head list; ++ nid_t ino; ++}; ++ ++struct dir_inode_entry { ++ struct list_head list; ++ struct inode *inode; ++}; ++ ++struct fsync_inode_entry { ++ struct list_head list; ++ struct inode *inode; ++ block_t blkaddr; ++}; ++ ++#define nats_in_cursum(sum) (le16_to_cpu(sum->n_nats)) ++#define sits_in_cursum(sum) (le16_to_cpu(sum->n_sits)) ++ ++#define nat_in_journal(sum, i) (sum->nat_j.entries[i].ne) ++#define nid_in_journal(sum, i) (sum->nat_j.entries[i].nid) ++#define sit_in_journal(sum, i) (sum->sit_j.entries[i].se) ++#define segno_in_journal(sum, i) (sum->sit_j.entries[i].segno) ++ ++static inline int update_nats_in_cursum(struct f2fs_summary_block *rs, int i) ++{ ++ int before = nats_in_cursum(rs); ++ rs->n_nats = cpu_to_le16(before + i); ++ return before; ++} ++ ++static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i) ++{ ++ int before = sits_in_cursum(rs); ++ rs->n_sits = cpu_to_le16(before + i); ++ return before; ++} ++ ++/** ++ * For INODE and NODE manager ++ */ ++#define XATTR_NODE_OFFSET (-1) ++#define RDONLY_NODE 1 ++#define F2FS_LINK_MAX 32000 ++ ++struct extent_info { ++ rwlock_t ext_lock; ++ unsigned int fofs; ++ u32 blk_addr; ++ unsigned int len; ++}; ++ ++#define FADVISE_COLD_BIT 0x01 ++/* ++ * i_advise uses FADVISE_XXX_BIT. We can add additional hints later. ++ */ ++struct f2fs_inode_info { ++ struct inode vfs_inode; ++ unsigned long i_flags; ++ unsigned long flags; ++ unsigned long long data_version; ++ atomic_t dirty_dents; ++ unsigned int current_depth; ++ f2fs_hash_t chash; ++ unsigned int clevel; ++ nid_t i_xattr_nid; ++ struct extent_info ext; ++ umode_t i_acl_mode; ++ unsigned char i_advise; /* If true, this is cold data */ ++}; ++ ++static inline void get_extent_info(struct extent_info *ext, ++ struct f2fs_extent i_ext) ++{ ++ write_lock(&ext->ext_lock); ++ ext->fofs = le32_to_cpu(i_ext.fofs); ++ ext->blk_addr = le32_to_cpu(i_ext.blk_addr); ++ ext->len = le32_to_cpu(i_ext.len); ++ write_unlock(&ext->ext_lock); ++} ++ ++static inline void set_raw_extent(struct extent_info *ext, ++ struct f2fs_extent *i_ext) ++{ ++ read_lock(&ext->ext_lock); ++ i_ext->fofs = cpu_to_le32(ext->fofs); ++ i_ext->blk_addr = cpu_to_le32(ext->blk_addr); ++ i_ext->len = cpu_to_le32(ext->len); ++ read_unlock(&ext->ext_lock); ++} ++ ++struct f2fs_nm_info { ++ block_t nat_blkaddr; /* base disk address of NAT */ ++ unsigned int nat_segs; /* the number of nat segments */ ++ unsigned int nat_blocks; /* the number of nat blocks of ++ one size */ ++ nid_t max_nid; ++ unsigned int nat_cnt; /* the number of nodes in NAT Buffer */ ++ struct radix_tree_root nat_root; ++ rwlock_t nat_tree_lock; /* Protect nat_tree_lock */ ++ struct list_head nat_entries; /* cached nat entry list (clean) */ ++ struct list_head dirty_nat_entries; /* cached nat entry list (dirty) */ ++ ++ unsigned int fcnt; /* the number of free node id */ ++ struct mutex build_lock; /* lock for build free nids */ ++ ++ int nat_upd_blkoff[3]; /* Block offset ++ in the current journal segment ++ where the last NAT update happened */ ++ int lst_upd_blkoff[3]; /* Block offset ++ in current journal segment */ ++ ++ unsigned int written_valid_node_count; ++ unsigned int written_valid_inode_count; ++ char *nat_bitmap; /* NAT bitmap pointer */ ++ int bitmap_size; /* bitmap size */ ++ ++ nid_t init_scan_nid; /* the first nid to be scanned */ ++ nid_t next_scan_nid; /* the next nid to be scanned */ ++ struct list_head free_nid_list; ++ spinlock_t free_nid_list_lock; /* Protect free nid list */ ++}; ++ ++struct dnode_of_data { ++ struct inode *inode; ++ struct page *inode_page; ++ struct page *node_page; ++ nid_t nid; ++ unsigned int ofs_in_node; ++ bool inode_page_locked; ++ block_t data_blkaddr; ++}; ++ ++static inline void set_new_dnode(struct dnode_of_data *dn, struct inode *inode, ++ struct page *ipage, struct page *npage, nid_t nid) ++{ ++ dn->inode = inode; ++ dn->inode_page = ipage; ++ dn->node_page = npage; ++ dn->nid = nid; ++ dn->inode_page_locked = 0; ++} ++ ++/** ++ * For SIT manager ++ */ ++#define NR_CURSEG_DATA_TYPE (3) ++#define NR_CURSEG_NODE_TYPE (3) ++#define NR_CURSEG_TYPE (NR_CURSEG_DATA_TYPE + NR_CURSEG_NODE_TYPE) ++ ++enum { ++ CURSEG_HOT_DATA = 0, ++ CURSEG_WARM_DATA, ++ CURSEG_COLD_DATA, ++ CURSEG_HOT_NODE, ++ CURSEG_WARM_NODE, ++ CURSEG_COLD_NODE, ++ NO_CHECK_TYPE ++}; ++ ++struct f2fs_sm_info { ++ /* SIT information */ ++ struct sit_info *sit_info; ++ ++ /* Free segmap infomation */ ++ struct free_segmap_info *free_info; ++ ++ /* Dirty segments list information for GC victim */ ++ struct dirty_seglist_info *dirty_info; ++ ++ /* Current working segments(i.e. logging point) information array */ ++ struct curseg_info *curseg_array; ++ ++ /* list head of all under-writeback pages for flush handling */ ++ struct list_head wblist_head; ++ spinlock_t wblist_lock; ++ ++ block_t seg0_blkaddr; ++ block_t main_blkaddr; ++ unsigned int segment_count; ++ unsigned int rsvd_segment_count; ++ unsigned int main_segment_count; ++ block_t ssa_blkaddr; ++ unsigned int segment_count_ssa; ++}; ++ ++/** ++ * For Garbage Collection ++ */ ++struct f2fs_gc_info { ++#ifdef CONFIG_F2FS_STAT_FS ++ struct list_head stat_list; ++ struct f2fs_stat_info *stat_info; ++#endif ++ int cause; ++ int rsvd_segment_count; ++ int overp_segment_count; ++}; ++ ++/** ++ * For directory operation ++ */ ++#define F2FS_INODE_SIZE (17 * 4 + F2FS_MAX_NAME_LEN) ++#define NODE_DIR1_BLOCK (ADDRS_PER_INODE + 1) ++#define NODE_DIR2_BLOCK (ADDRS_PER_INODE + 2) ++#define NODE_IND1_BLOCK (ADDRS_PER_INODE + 3) ++#define NODE_IND2_BLOCK (ADDRS_PER_INODE + 4) ++#define NODE_DIND_BLOCK (ADDRS_PER_INODE + 5) ++ ++/** ++ * For superblock ++ */ ++enum count_type { ++ F2FS_WRITEBACK, ++ F2FS_DIRTY_DENTS, ++ F2FS_DIRTY_NODES, ++ F2FS_DIRTY_META, ++ NR_COUNT_TYPE, ++}; ++ ++/* ++ * FS_LOCK nesting subclasses for the lock validator: ++ * ++ * The locking order between these classes is ++ * RENAME -> DENTRY_OPS -> DATA_WRITE -> DATA_NEW ++ * -> DATA_TRUNC -> NODE_WRITE -> NODE_NEW -> NODE_TRUNC ++ */ ++enum lock_type { ++ RENAME, /* for renaming operations */ ++ DENTRY_OPS, /* for directory operations */ ++ DATA_WRITE, /* for data write */ ++ DATA_NEW, /* for data allocation */ ++ DATA_TRUNC, /* for data truncate */ ++ NODE_NEW, /* for node allocation */ ++ NODE_TRUNC, /* for node truncate */ ++ NODE_WRITE, /* for node write */ ++ NR_LOCK_TYPE, ++}; ++ ++/* ++ * The below are the page types of bios used in submti_bio(). ++ * The available types are: ++ * DATA User data pages. It operates as async mode. ++ * NODE Node pages. It operates as async mode. ++ * META FS metadata pages such as SIT, NAT, CP. ++ * NR_PAGE_TYPE The number of page types. ++ * META_FLUSH Make sure the previous pages are written ++ * with waiting the bio's completion ++ * ... Only can be used with META. ++ */ ++enum page_type { ++ DATA, ++ NODE, ++ META, ++ NR_PAGE_TYPE, ++ META_FLUSH, ++}; ++ ++struct f2fs_sb_info { ++ struct super_block *sb; /* Pointer to VFS super block */ ++ int s_dirty; ++ struct f2fs_super_block *raw_super; /* Pointer to the super block ++ in the buffer */ ++ struct buffer_head *raw_super_buf; /* Buffer containing ++ the f2fs raw super block */ ++ struct f2fs_checkpoint *ckpt; /* Pointer to the checkpoint ++ in the buffer */ ++ struct mutex orphan_inode_mutex; ++ spinlock_t dir_inode_lock; ++ struct mutex cp_mutex; ++ /* orphan Inode list to be written in Journal block during CP */ ++ struct list_head orphan_inode_list; ++ struct list_head dir_inode_list; ++ unsigned int n_orphans, n_dirty_dirs; ++ ++ unsigned int log_sectorsize; ++ unsigned int log_sectors_per_block; ++ unsigned int log_blocksize; ++ unsigned int blocksize; ++ unsigned int root_ino_num; /* Root Inode Number*/ ++ unsigned int node_ino_num; /* Root Inode Number*/ ++ unsigned int meta_ino_num; /* Root Inode Number*/ ++ unsigned int log_blocks_per_seg; ++ unsigned int blocks_per_seg; ++ unsigned int segs_per_sec; ++ unsigned int secs_per_zone; ++ unsigned int total_sections; ++ unsigned int total_node_count; ++ unsigned int total_valid_node_count; ++ unsigned int total_valid_inode_count; ++ unsigned int segment_count[2]; ++ unsigned int block_count[2]; ++ unsigned int last_victim[2]; ++ int active_logs; ++ block_t user_block_count; ++ block_t total_valid_block_count; ++ block_t alloc_valid_block_count; ++ block_t last_valid_block_count; ++ atomic_t nr_pages[NR_COUNT_TYPE]; ++ ++ struct f2fs_mount_info mount_opt; ++ ++ /* related to NM */ ++ struct f2fs_nm_info *nm_info; /* Node Manager information */ ++ ++ /* related to SM */ ++ struct f2fs_sm_info *sm_info; /* Segment Manager ++ information */ ++ int total_hit_ext, read_hit_ext; ++ int rr_flush; ++ ++ /* related to GC */ ++ struct proc_dir_entry *s_proc; ++ struct f2fs_gc_info *gc_info; /* Garbage Collector ++ information */ ++ struct mutex gc_mutex; /* mutex for GC */ ++ struct mutex fs_lock[NR_LOCK_TYPE]; /* mutex for GP */ ++ struct mutex write_inode; /* mutex for write inode */ ++ struct mutex writepages; /* mutex for writepages() */ ++ struct f2fs_gc_kthread *gc_thread; /* GC thread */ ++ int bg_gc; ++ int last_gc_status; ++ int por_doing; ++ ++ struct inode *node_inode; ++ struct inode *meta_inode; ++ ++ struct bio *bio[NR_PAGE_TYPE]; ++ sector_t last_block_in_bio[NR_PAGE_TYPE]; ++ struct rw_semaphore bio_sem; ++ spinlock_t stat_lock; /* lock for handling the number ++ of valid blocks and ++ valid nodes */ ++}; ++ ++/** ++ * Inline functions ++ */ ++static inline struct f2fs_inode_info *F2FS_I(struct inode *inode) ++{ ++ return container_of(inode, struct f2fs_inode_info, vfs_inode); ++} ++ ++static inline struct f2fs_sb_info *F2FS_SB(struct super_block *sb) ++{ ++ return sb->s_fs_info; ++} ++ ++static inline struct f2fs_super_block *F2FS_RAW_SUPER(struct f2fs_sb_info *sbi) ++{ ++ return (struct f2fs_super_block *)(sbi->raw_super); ++} ++ ++static inline struct f2fs_checkpoint *F2FS_CKPT(struct f2fs_sb_info *sbi) ++{ ++ return (struct f2fs_checkpoint *)(sbi->ckpt); ++} ++ ++static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi) ++{ ++ return (struct f2fs_nm_info *)(sbi->nm_info); ++} ++ ++static inline struct f2fs_sm_info *SM_I(struct f2fs_sb_info *sbi) ++{ ++ return (struct f2fs_sm_info *)(sbi->sm_info); ++} ++ ++static inline struct sit_info *SIT_I(struct f2fs_sb_info *sbi) ++{ ++ return (struct sit_info *)(SM_I(sbi)->sit_info); ++} ++ ++static inline struct free_segmap_info *FREE_I(struct f2fs_sb_info *sbi) ++{ ++ return (struct free_segmap_info *)(SM_I(sbi)->free_info); ++} ++ ++static inline struct dirty_seglist_info *DIRTY_I(struct f2fs_sb_info *sbi) ++{ ++ return (struct dirty_seglist_info *)(SM_I(sbi)->dirty_info); ++} ++ ++static inline void F2FS_SET_SB_DIRT(struct f2fs_sb_info *sbi) ++{ ++ sbi->s_dirty = 1; ++} ++ ++static inline void F2FS_RESET_SB_DIRT(struct f2fs_sb_info *sbi) ++{ ++ sbi->s_dirty = 0; ++} ++ ++static inline void mutex_lock_op(struct f2fs_sb_info *sbi, enum lock_type t) ++{ ++ mutex_lock_nested(&sbi->fs_lock[t], t); ++} ++ ++static inline void mutex_unlock_op(struct f2fs_sb_info *sbi, enum lock_type t) ++{ ++ mutex_unlock(&sbi->fs_lock[t]); ++} ++ ++/** ++ * Check whether the given nid is within node id range. ++ */ ++static inline void check_nid_range(struct f2fs_sb_info *sbi, nid_t nid) ++{ ++ BUG_ON((nid >= NM_I(sbi)->max_nid)); ++} ++ ++#define F2FS_DEFAULT_ALLOCATED_BLOCKS 1 ++ ++/** ++ * Check whether the inode has blocks or not ++ */ ++static inline int F2FS_HAS_BLOCKS(struct inode *inode) ++{ ++ if (F2FS_I(inode)->i_xattr_nid) ++ return (inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS + 1); ++ else ++ return (inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS); ++} ++ ++static inline bool inc_valid_block_count(struct f2fs_sb_info *sbi, ++ struct inode *inode, blkcnt_t count) ++{ ++ block_t valid_block_count; ++ ++ spin_lock(&sbi->stat_lock); ++ valid_block_count = ++ sbi->total_valid_block_count + (block_t)count; ++ if (valid_block_count > sbi->user_block_count) { ++ spin_unlock(&sbi->stat_lock); ++ return false; ++ } ++ inode->i_blocks += count; ++ sbi->total_valid_block_count = valid_block_count; ++ sbi->alloc_valid_block_count += (block_t)count; ++ spin_unlock(&sbi->stat_lock); ++ return true; ++} ++ ++static inline int dec_valid_block_count(struct f2fs_sb_info *sbi, ++ struct inode *inode, ++ blkcnt_t count) ++{ ++ spin_lock(&sbi->stat_lock); ++ BUG_ON(sbi->total_valid_block_count < (block_t) count); ++ BUG_ON(inode->i_blocks < count); ++ inode->i_blocks -= count; ++ sbi->total_valid_block_count -= (block_t)count; ++ spin_unlock(&sbi->stat_lock); ++ return 0; ++} ++ ++static inline void inc_page_count(struct f2fs_sb_info *sbi, int count_type) ++{ ++ atomic_inc(&sbi->nr_pages[count_type]); ++ F2FS_SET_SB_DIRT(sbi); ++} ++ ++static inline void inode_inc_dirty_dents(struct inode *inode) ++{ ++ atomic_inc(&F2FS_I(inode)->dirty_dents); ++} ++ ++static inline void dec_page_count(struct f2fs_sb_info *sbi, int count_type) ++{ ++ atomic_dec(&sbi->nr_pages[count_type]); ++} ++ ++static inline void inode_dec_dirty_dents(struct inode *inode) ++{ ++ atomic_dec(&F2FS_I(inode)->dirty_dents); ++} ++ ++static inline int get_pages(struct f2fs_sb_info *sbi, int count_type) ++{ ++ return atomic_read(&sbi->nr_pages[count_type]); ++} ++ ++static inline block_t valid_user_blocks(struct f2fs_sb_info *sbi) ++{ ++ block_t ret; ++ spin_lock(&sbi->stat_lock); ++ ret = sbi->total_valid_block_count; ++ spin_unlock(&sbi->stat_lock); ++ return ret; ++} ++ ++static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag) ++{ ++ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); ++ ++ /* return NAT or SIT bitmap */ ++ if (flag == NAT_BITMAP) ++ return le32_to_cpu(ckpt->nat_ver_bitmap_bytesize); ++ else if (flag == SIT_BITMAP) ++ return le32_to_cpu(ckpt->sit_ver_bitmap_bytesize); ++ ++ return 0; ++} ++ ++static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag) ++{ ++ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); ++ int offset = (flag == NAT_BITMAP) ? ckpt->sit_ver_bitmap_bytesize : 0; ++ return &ckpt->sit_nat_version_bitmap + offset; ++} ++ ++static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi) ++{ ++ block_t start_addr; ++ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); ++ unsigned long long ckpt_version = le64_to_cpu(ckpt->checkpoint_ver); ++ ++ start_addr = le64_to_cpu(F2FS_RAW_SUPER(sbi)->start_segment_checkpoint); ++ ++ /* ++ * odd numbered checkpoint shoukd at cp segment 0 ++ * and even segent must be at cp segment 1 ++ */ ++ if (!(ckpt_version & 1)) ++ start_addr += sbi->blocks_per_seg; ++ ++ return start_addr; ++} ++ ++static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi) ++{ ++ return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum); ++} ++ ++static inline bool inc_valid_node_count(struct f2fs_sb_info *sbi, ++ struct inode *inode, ++ unsigned int count) ++{ ++ block_t valid_block_count; ++ unsigned int valid_node_count; ++ ++ spin_lock(&sbi->stat_lock); ++ ++ valid_block_count = sbi->total_valid_block_count + (block_t)count; ++ sbi->alloc_valid_block_count += (block_t)count; ++ valid_node_count = sbi->total_valid_node_count + count; ++ ++ if (valid_block_count > sbi->user_block_count) { ++ spin_unlock(&sbi->stat_lock); ++ return false; ++ } ++ ++ if (valid_node_count > sbi->total_node_count) { ++ spin_unlock(&sbi->stat_lock); ++ return false; ++ } ++ ++ if (inode) ++ inode->i_blocks += count; ++ sbi->total_valid_node_count = valid_node_count; ++ sbi->total_valid_block_count = valid_block_count; ++ spin_unlock(&sbi->stat_lock); ++ ++ return true; ++} ++ ++static inline void dec_valid_node_count(struct f2fs_sb_info *sbi, ++ struct inode *inode, ++ unsigned int count) ++{ ++ spin_lock(&sbi->stat_lock); ++ ++ BUG_ON(sbi->total_valid_block_count < count); ++ BUG_ON(sbi->total_valid_node_count < count); ++ BUG_ON(inode->i_blocks < count); ++ ++ inode->i_blocks -= count; ++ sbi->total_valid_node_count -= count; ++ sbi->total_valid_block_count -= (block_t)count; ++ ++ spin_unlock(&sbi->stat_lock); ++} ++ ++static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi) ++{ ++ unsigned int ret; ++ spin_lock(&sbi->stat_lock); ++ ret = sbi->total_valid_node_count; ++ spin_unlock(&sbi->stat_lock); ++ return ret; ++} ++ ++static inline void inc_valid_inode_count(struct f2fs_sb_info *sbi) ++{ ++ spin_lock(&sbi->stat_lock); ++ BUG_ON(sbi->total_valid_inode_count == sbi->total_node_count); ++ sbi->total_valid_inode_count++; ++ spin_unlock(&sbi->stat_lock); ++} ++ ++static inline int dec_valid_inode_count(struct f2fs_sb_info *sbi) ++{ ++ spin_lock(&sbi->stat_lock); ++ BUG_ON(!sbi->total_valid_inode_count); ++ sbi->total_valid_inode_count--; ++ spin_unlock(&sbi->stat_lock); ++ return 0; ++} ++ ++static inline unsigned int valid_inode_count(struct f2fs_sb_info *sbi) ++{ ++ unsigned int ret; ++ spin_lock(&sbi->stat_lock); ++ ret = sbi->total_valid_inode_count; ++ spin_unlock(&sbi->stat_lock); ++ return ret; ++} ++ ++static inline void f2fs_put_page(struct page *page, int unlock) ++{ ++ if (!page || IS_ERR(page)) ++ return; ++ ++ if (unlock) { ++ BUG_ON(!PageLocked(page)); ++ unlock_page(page); ++ } ++ page_cache_release(page); ++} ++ ++static inline void f2fs_put_dnode(struct dnode_of_data *dn) ++{ ++ if (dn->node_page) ++ f2fs_put_page(dn->node_page, 1); ++ if (dn->inode_page && dn->node_page != dn->inode_page) ++ f2fs_put_page(dn->inode_page, 0); ++ dn->node_page = NULL; ++ dn->inode_page = NULL; ++} ++ ++static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name, ++ size_t size, void (*ctor)(void *)) ++{ ++ return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, ctor); ++} ++ ++#define RAW_IS_INODE(p) ((p)->footer.nid == (p)->footer.ino) ++ ++static inline bool IS_INODE(struct page *page) ++{ ++ struct f2fs_node *p = (struct f2fs_node *)page_address(page); ++ return RAW_IS_INODE(p); ++} ++ ++static inline __le32 *blkaddr_in_node(struct f2fs_node *node) ++{ ++ return RAW_IS_INODE(node) ? node->i.i_addr : node->dn.addr; ++} ++ ++static inline block_t datablock_addr(struct page *node_page, ++ unsigned int offset) ++{ ++ struct f2fs_node *raw_node; ++ __le32 *addr_array; ++ raw_node = (struct f2fs_node *)page_address(node_page); ++ addr_array = blkaddr_in_node(raw_node); ++ return le32_to_cpu(addr_array[offset]); ++} ++ ++static inline int f2fs_test_bit(unsigned int nr, char *addr) ++{ ++ int mask; ++ ++ addr += (nr >> 3); ++ mask = 1 << (7 - (nr & 0x07)); ++ return mask & *addr; ++} ++ ++static inline int f2fs_set_bit(unsigned int nr, char *addr) ++{ ++ int mask; ++ int ret; ++ ++ addr += (nr >> 3); ++ mask = 1 << (7 - (nr & 0x07)); ++ ret = mask & *addr; ++ *addr |= mask; ++ return ret; ++} ++ ++static inline int f2fs_clear_bit(unsigned int nr, char *addr) ++{ ++ int mask; ++ int ret; ++ ++ addr += (nr >> 3); ++ mask = 1 << (7 - (nr & 0x07)); ++ ret = mask & *addr; ++ *addr &= ~mask; ++ return ret; ++} ++ ++enum { ++ FI_NEW_INODE, ++ FI_NEED_CP, ++ FI_INC_LINK, ++ FI_ACL_MODE, ++ FI_NO_ALLOC, ++}; ++ ++static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag) ++{ ++ set_bit(flag, &fi->flags); ++} ++ ++static inline int is_inode_flag_set(struct f2fs_inode_info *fi, int flag) ++{ ++ return test_bit(flag, &fi->flags); ++} ++ ++static inline void clear_inode_flag(struct f2fs_inode_info *fi, int flag) ++{ ++ clear_bit(flag, &fi->flags); ++} ++ ++static inline void set_acl_inode(struct f2fs_inode_info *fi, umode_t mode) ++{ ++ fi->i_acl_mode = mode; ++ set_inode_flag(fi, FI_ACL_MODE); ++} ++ ++static inline int cond_clear_inode_flag(struct f2fs_inode_info *fi, int flag) ++{ ++ if (is_inode_flag_set(fi, FI_ACL_MODE)) { ++ clear_inode_flag(fi, FI_ACL_MODE); ++ return 1; ++ } ++ return 0; ++} ++ ++/** ++ * file.c ++ */ ++int f2fs_sync_file(struct file *, loff_t, loff_t, int); ++void truncate_data_blocks(struct dnode_of_data *); ++void f2fs_truncate(struct inode *); ++int f2fs_setattr(struct dentry *, struct iattr *); ++int truncate_hole(struct inode *, pgoff_t, pgoff_t); ++long f2fs_ioctl(struct file *, unsigned int, unsigned long); ++ ++/** ++ * inode.c ++ */ ++void f2fs_set_inode_flags(struct inode *); ++struct inode *f2fs_iget_nowait(struct super_block *, unsigned long); ++struct inode *f2fs_iget(struct super_block *, unsigned long); ++void update_inode(struct inode *, struct page *); ++int f2fs_write_inode(struct inode *, struct writeback_control *); ++void f2fs_evict_inode(struct inode *); ++ ++/** ++ * dir.c ++ */ ++struct f2fs_dir_entry *f2fs_find_entry(struct inode *, struct qstr *, ++ struct page **); ++struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **); ++void f2fs_set_link(struct inode *, struct f2fs_dir_entry *, ++ struct page *, struct inode *); ++void init_dent_inode(struct dentry *, struct page *); ++int f2fs_add_link(struct dentry *, struct inode *); ++void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *); ++int f2fs_make_empty(struct inode *, struct inode *); ++bool f2fs_empty_dir(struct inode *); ++ ++/** ++ * super.c ++ */ ++int f2fs_sync_fs(struct super_block *, int); ++ ++/** ++ * hash.c ++ */ ++f2fs_hash_t f2fs_dentry_hash(const char *, int); ++ ++/** ++ * node.c ++ */ ++struct dnode_of_data; ++struct node_info; ++ ++int is_checkpointed_node(struct f2fs_sb_info *, nid_t); ++void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *); ++int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int); ++int truncate_inode_blocks(struct inode *, pgoff_t); ++int remove_inode_page(struct inode *); ++int new_inode_page(struct inode *, struct dentry *); ++struct page *new_node_page(struct dnode_of_data *, unsigned int); ++void ra_node_page(struct f2fs_sb_info *, nid_t); ++struct page *get_node_page(struct f2fs_sb_info *, pgoff_t); ++struct page *get_node_page_ra(struct page *, int); ++void sync_inode_page(struct dnode_of_data *); ++int sync_node_pages(struct f2fs_sb_info *, nid_t, struct writeback_control *); ++bool alloc_nid(struct f2fs_sb_info *, nid_t *); ++void alloc_nid_done(struct f2fs_sb_info *, nid_t); ++void alloc_nid_failed(struct f2fs_sb_info *, nid_t); ++void recover_node_page(struct f2fs_sb_info *, struct page *, ++ struct f2fs_summary *, struct node_info *, block_t); ++int recover_inode_page(struct f2fs_sb_info *, struct page *); ++int restore_node_summary(struct f2fs_sb_info *, unsigned int, ++ struct f2fs_summary_block *); ++void flush_nat_entries(struct f2fs_sb_info *); ++int build_node_manager(struct f2fs_sb_info *); ++void destroy_node_manager(struct f2fs_sb_info *); ++int create_node_manager_caches(void); ++void destroy_node_manager_caches(void); ++ ++/** ++ * segment.c ++ */ ++void f2fs_balance_fs(struct f2fs_sb_info *); ++void invalidate_blocks(struct f2fs_sb_info *, block_t); ++void locate_dirty_segment(struct f2fs_sb_info *, unsigned int); ++void clear_prefree_segments(struct f2fs_sb_info *); ++int npages_for_summary_flush(struct f2fs_sb_info *); ++void allocate_new_segments(struct f2fs_sb_info *); ++struct page *get_sum_page(struct f2fs_sb_info *, unsigned int); ++struct bio *f2fs_bio_alloc(struct block_device *, sector_t, int, gfp_t); ++void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool sync); ++int write_meta_page(struct f2fs_sb_info *, struct page *, ++ struct writeback_control *); ++void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int, ++ block_t, block_t *); ++void write_data_page(struct inode *, struct page *, struct dnode_of_data*, ++ block_t, block_t *); ++void rewrite_data_page(struct f2fs_sb_info *, struct page *, block_t); ++void recover_data_page(struct f2fs_sb_info *, struct page *, ++ struct f2fs_summary *, block_t, block_t); ++void rewrite_node_page(struct f2fs_sb_info *, struct page *, ++ struct f2fs_summary *, block_t, block_t); ++void write_data_summaries(struct f2fs_sb_info *, block_t); ++void write_node_summaries(struct f2fs_sb_info *, block_t); ++int lookup_journal_in_cursum(struct f2fs_summary_block *, ++ int, unsigned int, int); ++void flush_sit_entries(struct f2fs_sb_info *); ++int build_segment_manager(struct f2fs_sb_info *); ++void reset_victim_segmap(struct f2fs_sb_info *); ++void destroy_segment_manager(struct f2fs_sb_info *); ++ ++/** ++ * checkpoint.c ++ */ ++struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t); ++struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t); ++long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long); ++int check_orphan_space(struct f2fs_sb_info *); ++void add_orphan_inode(struct f2fs_sb_info *, nid_t); ++void remove_orphan_inode(struct f2fs_sb_info *, nid_t); ++int recover_orphan_inodes(struct f2fs_sb_info *); ++int get_valid_checkpoint(struct f2fs_sb_info *); ++void set_dirty_dir_page(struct inode *, struct page *); ++void remove_dirty_dir_inode(struct inode *); ++void sync_dirty_dir_inodes(struct f2fs_sb_info *); ++void block_operations(struct f2fs_sb_info *); ++void write_checkpoint(struct f2fs_sb_info *, bool, bool); ++void init_orphan_info(struct f2fs_sb_info *); ++int create_checkpoint_caches(void); ++void destroy_checkpoint_caches(void); ++ ++/** ++ * data.c ++ */ ++int reserve_new_block(struct dnode_of_data *); ++void update_extent_cache(block_t, struct dnode_of_data *); ++struct page *find_data_page(struct inode *, pgoff_t); ++struct page *get_lock_data_page(struct inode *, pgoff_t); ++struct page *get_new_data_page(struct inode *, pgoff_t, bool); ++int f2fs_readpage(struct f2fs_sb_info *, struct page *, block_t, int); ++int do_write_data_page(struct page *); ++ ++/** ++ * gc.c ++ */ ++int start_gc_thread(struct f2fs_sb_info *); ++void stop_gc_thread(struct f2fs_sb_info *); ++block_t start_bidx_of_node(unsigned int); ++int f2fs_gc(struct f2fs_sb_info *, int); ++#ifdef CONFIG_F2FS_STAT_FS ++void f2fs_update_stat(struct f2fs_sb_info *); ++void f2fs_update_gc_metric(struct f2fs_sb_info *); ++int f2fs_stat_init(struct f2fs_sb_info *); ++void f2fs_stat_exit(struct f2fs_sb_info *); ++#endif ++int build_gc_manager(struct f2fs_sb_info *); ++void destroy_gc_manager(struct f2fs_sb_info *); ++int create_gc_caches(void); ++void destroy_gc_caches(void); ++ ++/** ++ * recovery.c ++ */ ++void recover_fsync_data(struct f2fs_sb_info *); ++bool space_for_roll_forward(struct f2fs_sb_info *); ++ ++extern const struct file_operations f2fs_dir_operations; ++extern const struct file_operations f2fs_file_operations; ++extern const struct inode_operations f2fs_file_inode_operations; ++extern const struct address_space_operations f2fs_dblock_aops; ++extern const struct address_space_operations f2fs_node_aops; ++extern const struct address_space_operations f2fs_meta_aops; ++extern const struct inode_operations f2fs_dir_inode_operations; ++extern const struct inode_operations f2fs_symlink_inode_operations; ++extern const struct inode_operations f2fs_special_inode_operations; ++#endif +diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h +new file mode 100644 +index 0000000..99ac689 +--- /dev/null ++++ b/fs/f2fs/node.h +@@ -0,0 +1,330 @@ ++/** ++ * fs/f2fs/node.h ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#define START_NID(nid) ((nid / NAT_ENTRY_PER_BLOCK) * NAT_ENTRY_PER_BLOCK) ++#define NAT_BLOCK_OFFSET(start_nid) (start_nid / NAT_ENTRY_PER_BLOCK) ++ ++#define FREE_NID_PAGES 4 ++#define MAX_FREE_NIDS (NAT_ENTRY_PER_BLOCK * FREE_NID_PAGES) ++ ++#define MAX_RA_NODE 128 /* Max. readahead size for node */ ++#define NM_WOUT_THRESHOLD (64 * NAT_ENTRY_PER_BLOCK) ++#define NATVEC_SIZE 64 ++ ++/** ++ * For node information ++ */ ++struct node_info { ++ nid_t nid; /* node id */ ++ nid_t ino; /* inode number of the node's owner */ ++ block_t blk_addr; /* block address of the node */ ++ unsigned char version; /* version of the node */ ++}; ++ ++static inline unsigned char inc_node_version(unsigned char version) ++{ ++ return ++version; ++} ++ ++struct nat_entry { ++ struct list_head list; /* for clean or dirty nat list */ ++ bool checkpointed; ++ struct node_info ni; ++}; ++ ++#define nat_get_nid(nat) (nat->ni.nid) ++#define nat_set_nid(nat, n) (nat->ni.nid = n) ++#define nat_get_blkaddr(nat) (nat->ni.blk_addr) ++#define nat_set_blkaddr(nat, b) (nat->ni.blk_addr = b) ++#define nat_get_ino(nat) (nat->ni.ino) ++#define nat_set_ino(nat, i) (nat->ni.ino = i) ++#define nat_get_version(nat) (nat->ni.version) ++#define nat_set_version(nat, v) (nat->ni.version = v) ++#define __set_nat_cache_dirty(nm_i, ne) \ ++ list_move_tail(&ne->list, &nm_i->dirty_nat_entries); ++#define __clear_nat_cache_dirty(nm_i, ne) \ ++ list_move_tail(&ne->list, &nm_i->nat_entries); ++ ++static inline void node_info_from_raw_nat(struct node_info *ni, ++ struct f2fs_nat_entry *raw_ne) ++{ ++ ni->ino = le32_to_cpu(raw_ne->ino); ++ ni->blk_addr = le32_to_cpu(raw_ne->block_addr); ++ ni->version = raw_ne->version; ++} ++ ++/** ++ * For free nid mangement ++ */ ++enum nid_state { ++ NID_NEW, ++ NID_ALLOC ++}; ++ ++struct free_nid { ++ nid_t nid; ++ int state; ++ struct list_head list; ++}; ++ ++static inline int next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid) ++{ ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ struct free_nid *fnid; ++ ++ if (nm_i->fcnt <= 0) ++ return -1; ++ spin_lock(&nm_i->free_nid_list_lock); ++ fnid = list_entry(nm_i->free_nid_list.next, struct free_nid, list); ++ *nid = fnid->nid; ++ spin_unlock(&nm_i->free_nid_list_lock); ++ return 0; ++} ++ ++/** ++ * inline functions ++ */ ++static inline void get_nat_bitmap(struct f2fs_sb_info *sbi, void *addr) ++{ ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ memcpy(addr, nm_i->nat_bitmap, nm_i->bitmap_size); ++} ++ ++static inline pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start) ++{ ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ pgoff_t block_off; ++ pgoff_t block_addr; ++ int seg_off; ++ ++ block_off = NAT_BLOCK_OFFSET(start); ++ seg_off = block_off >> sbi->log_blocks_per_seg; ++ ++ block_addr = (pgoff_t)(nm_i->nat_blkaddr + ++ (seg_off << sbi->log_blocks_per_seg << 1) + ++ (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); ++ ++ if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) ++ block_addr += sbi->blocks_per_seg; ++ ++ return block_addr; ++} ++ ++static inline pgoff_t next_nat_addr(struct f2fs_sb_info *sbi, ++ pgoff_t block_addr) ++{ ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ ++ block_addr -= nm_i->nat_blkaddr; ++ if ((block_addr >> sbi->log_blocks_per_seg) % 2) ++ block_addr -= sbi->blocks_per_seg; ++ else ++ block_addr += sbi->blocks_per_seg; ++ ++ return block_addr + nm_i->nat_blkaddr; ++} ++ ++static inline void set_to_next_nat(struct f2fs_nm_info *nm_i, nid_t start_nid) ++{ ++ unsigned int block_off = NAT_BLOCK_OFFSET(start_nid); ++ ++ if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) ++ f2fs_clear_bit(block_off, nm_i->nat_bitmap); ++ else ++ f2fs_set_bit(block_off, nm_i->nat_bitmap); ++} ++ ++static inline void fill_node_footer(struct page *page, nid_t nid, ++ nid_t ino, unsigned int ofs, bool reset) ++{ ++ void *kaddr = page_address(page); ++ struct f2fs_node *rn = (struct f2fs_node *)kaddr; ++ if (reset) ++ memset(rn, 0, sizeof(*rn)); ++ rn->footer.nid = cpu_to_le32(nid); ++ rn->footer.ino = cpu_to_le32(ino); ++ rn->footer.flag = cpu_to_le32(ofs << OFFSET_BIT_SHIFT); ++} ++ ++static inline void copy_node_footer(struct page *dst, struct page *src) ++{ ++ void *src_addr = page_address(src); ++ void *dst_addr = page_address(dst); ++ struct f2fs_node *src_rn = (struct f2fs_node *)src_addr; ++ struct f2fs_node *dst_rn = (struct f2fs_node *)dst_addr; ++ memcpy(&dst_rn->footer, &src_rn->footer, sizeof(struct node_footer)); ++} ++ ++static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); ++ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); ++ void *kaddr = page_address(page); ++ struct f2fs_node *rn = (struct f2fs_node *)kaddr; ++ rn->footer.cp_ver = ckpt->checkpoint_ver; ++ rn->footer.next_blkaddr = blkaddr; ++} ++ ++static inline nid_t ino_of_node(struct page *node_page) ++{ ++ void *kaddr = page_address(node_page); ++ struct f2fs_node *rn = (struct f2fs_node *)kaddr; ++ return le32_to_cpu(rn->footer.ino); ++} ++ ++static inline nid_t nid_of_node(struct page *node_page) ++{ ++ void *kaddr = page_address(node_page); ++ struct f2fs_node *rn = (struct f2fs_node *)kaddr; ++ return le32_to_cpu(rn->footer.nid); ++} ++ ++static inline unsigned int ofs_of_node(struct page *node_page) ++{ ++ void *kaddr = page_address(node_page); ++ struct f2fs_node *rn = (struct f2fs_node *)kaddr; ++ unsigned flag = le32_to_cpu(rn->footer.flag); ++ return flag >> OFFSET_BIT_SHIFT; ++} ++ ++static inline unsigned long long cpver_of_node(struct page *node_page) ++{ ++ void *kaddr = page_address(node_page); ++ struct f2fs_node *rn = (struct f2fs_node *)kaddr; ++ return le64_to_cpu(rn->footer.cp_ver); ++} ++ ++static inline block_t next_blkaddr_of_node(struct page *node_page) ++{ ++ void *kaddr = page_address(node_page); ++ struct f2fs_node *rn = (struct f2fs_node *)kaddr; ++ return le32_to_cpu(rn->footer.next_blkaddr); ++} ++ ++static inline bool IS_DNODE(struct page *node_page) ++{ ++ unsigned int ofs = ofs_of_node(node_page); ++ if (ofs == 3 || ofs == 4 + NIDS_PER_BLOCK || ++ ofs == 5 + 2 * NIDS_PER_BLOCK) ++ return false; ++ if (ofs >= 6 + 2 * NIDS_PER_BLOCK) { ++ ofs -= 6 + 2 * NIDS_PER_BLOCK; ++ if ((long int)ofs % (NIDS_PER_BLOCK + 1)) ++ return false; ++ } ++ return true; ++} ++ ++static inline void set_nid(struct page *p, int off, nid_t nid, bool i) ++{ ++ struct f2fs_node *rn = (struct f2fs_node *)page_address(p); ++ ++ wait_on_page_writeback(p); ++ ++ if (i) ++ rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid); ++ else ++ rn->in.nid[off] = cpu_to_le32(nid); ++ set_page_dirty(p); ++} ++ ++static inline nid_t get_nid(struct page *p, int off, bool i) ++{ ++ struct f2fs_node *rn = (struct f2fs_node *)page_address(p); ++ if (i) ++ return le32_to_cpu(rn->i.i_nid[off - NODE_DIR1_BLOCK]); ++ return le32_to_cpu(rn->in.nid[off]); ++} ++ ++/** ++ * Coldness identification: ++ * - Mark cold files in f2fs_inode_info ++ * - Mark cold node blocks in their node footer ++ * - Mark cold data pages in page cache ++ */ ++static inline int is_cold_file(struct inode *inode) ++{ ++ return F2FS_I(inode)->i_advise & FADVISE_COLD_BIT; ++} ++ ++static inline int is_cold_data(struct page *page) ++{ ++ return PageChecked(page); ++} ++ ++static inline void set_cold_data(struct page *page) ++{ ++ SetPageChecked(page); ++} ++ ++static inline void clear_cold_data(struct page *page) ++{ ++ ClearPageChecked(page); ++} ++ ++static inline int is_cold_node(struct page *page) ++{ ++ void *kaddr = page_address(page); ++ struct f2fs_node *rn = (struct f2fs_node *)kaddr; ++ unsigned int flag = le32_to_cpu(rn->footer.flag); ++ return flag & (0x1 << COLD_BIT_SHIFT); ++} ++ ++static inline unsigned char is_fsync_dnode(struct page *page) ++{ ++ void *kaddr = page_address(page); ++ struct f2fs_node *rn = (struct f2fs_node *)kaddr; ++ unsigned int flag = le32_to_cpu(rn->footer.flag); ++ return flag & (0x1 << FSYNC_BIT_SHIFT); ++} ++ ++static inline unsigned char is_dent_dnode(struct page *page) ++{ ++ void *kaddr = page_address(page); ++ struct f2fs_node *rn = (struct f2fs_node *)kaddr; ++ unsigned int flag = le32_to_cpu(rn->footer.flag); ++ return flag & (0x1 << DENT_BIT_SHIFT); ++} ++ ++static inline void set_cold_node(struct inode *inode, struct page *page) ++{ ++ struct f2fs_node *rn = (struct f2fs_node *)page_address(page); ++ unsigned int flag = le32_to_cpu(rn->footer.flag); ++ ++ if (S_ISDIR(inode->i_mode)) ++ flag &= ~(0x1 << COLD_BIT_SHIFT); ++ else ++ flag |= (0x1 << COLD_BIT_SHIFT); ++ rn->footer.flag = cpu_to_le32(flag); ++} ++ ++static inline void set_fsync_mark(struct page *page, int mark) ++{ ++ void *kaddr = page_address(page); ++ struct f2fs_node *rn = (struct f2fs_node *)kaddr; ++ unsigned int flag = le32_to_cpu(rn->footer.flag); ++ if (mark) ++ flag |= (0x1 << FSYNC_BIT_SHIFT); ++ else ++ flag &= ~(0x1 << FSYNC_BIT_SHIFT); ++ rn->footer.flag = cpu_to_le32(flag); ++} ++ ++static inline void set_dentry_mark(struct page *page, int mark) ++{ ++ void *kaddr = page_address(page); ++ struct f2fs_node *rn = (struct f2fs_node *)kaddr; ++ unsigned int flag = le32_to_cpu(rn->footer.flag); ++ if (mark) ++ flag |= (0x1 << DENT_BIT_SHIFT); ++ else ++ flag &= ~(0x1 << DENT_BIT_SHIFT); ++ rn->footer.flag = cpu_to_le32(flag); ++} +diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h +new file mode 100644 +index 0000000..cd6268e +--- /dev/null ++++ b/fs/f2fs/segment.h +@@ -0,0 +1,594 @@ ++/** ++ * fs/f2fs/segment.h ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++/* constant macro */ ++#define NULL_SEGNO ((unsigned int)(~0)) ++#define SUM_TYPE_NODE (1) ++#define SUM_TYPE_DATA (0) ++ ++/* V: Logical segment # in volume, R: Relative segment # in main area */ ++#define GET_L2R_SEGNO(free_i, segno) (segno - free_i->start_segno) ++#define GET_R2L_SEGNO(free_i, segno) (segno + free_i->start_segno) ++ ++#define IS_DATASEG(t) \ ++ ((t == CURSEG_HOT_DATA) || (t == CURSEG_COLD_DATA) || \ ++ (t == CURSEG_WARM_DATA)) ++ ++#define IS_NODESEG(t) \ ++ ((t == CURSEG_HOT_NODE) || (t == CURSEG_COLD_NODE) || \ ++ (t == CURSEG_WARM_NODE)) ++ ++#define IS_CURSEG(sbi, segno) \ ++ ((segno == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) || \ ++ (segno == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) || \ ++ (segno == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno) || \ ++ (segno == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno) || \ ++ (segno == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno) || \ ++ (segno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno)) ++ ++#define IS_CURSEC(sbi, secno) \ ++ ((secno == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno / \ ++ sbi->segs_per_sec) || \ ++ (secno == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno / \ ++ sbi->segs_per_sec) || \ ++ (secno == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno / \ ++ sbi->segs_per_sec) || \ ++ (secno == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno / \ ++ sbi->segs_per_sec) || \ ++ (secno == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno / \ ++ sbi->segs_per_sec) || \ ++ (secno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \ ++ sbi->segs_per_sec)) \ ++ ++#define START_BLOCK(sbi, segno) \ ++ (SM_I(sbi)->seg0_blkaddr + \ ++ (GET_R2L_SEGNO(FREE_I(sbi), segno) << sbi->log_blocks_per_seg)) ++#define NEXT_FREE_BLKADDR(sbi, curseg) \ ++ (START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff) ++ ++#define MAIN_BASE_BLOCK(sbi) (SM_I(sbi)->main_blkaddr) ++ ++#define GET_SEGOFF_FROM_SEG0(sbi, blk_addr) \ ++ ((blk_addr) - SM_I(sbi)->seg0_blkaddr) ++#define GET_SEGNO_FROM_SEG0(sbi, blk_addr) \ ++ (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg) ++#define GET_SEGNO(sbi, blk_addr) \ ++ (((blk_addr == NULL_ADDR) || (blk_addr == NEW_ADDR)) ? \ ++ NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi), \ ++ GET_SEGNO_FROM_SEG0(sbi, blk_addr))) ++#define GET_SECNO(sbi, segno) \ ++ ((segno) / sbi->segs_per_sec) ++#define GET_ZONENO_FROM_SEGNO(sbi, segno) \ ++ ((segno / sbi->segs_per_sec) / sbi->secs_per_zone) ++ ++#define GET_SUM_BLOCK(sbi, segno) \ ++ ((sbi->sm_info->ssa_blkaddr) + segno) ++ ++#define GET_SUM_TYPE(footer) ((footer)->entry_type) ++#define SET_SUM_TYPE(footer, type) ((footer)->entry_type = type) ++ ++#define SIT_ENTRY_OFFSET(sit_i, segno) \ ++ (segno % sit_i->sents_per_block) ++#define SIT_BLOCK_OFFSET(sit_i, segno) \ ++ (segno / SIT_ENTRY_PER_BLOCK) ++#define START_SEGNO(sit_i, segno) \ ++ (SIT_BLOCK_OFFSET(sit_i, segno) * SIT_ENTRY_PER_BLOCK) ++#define f2fs_bitmap_size(nr) \ ++ (BITS_TO_LONGS(nr) * sizeof(unsigned long)) ++#define TOTAL_SEGS(sbi) (SM_I(sbi)->main_segment_count) ++ ++enum { ++ LFS = 0, ++ SSR ++}; ++ ++enum { ++ ALLOC_RIGHT = 0, ++ ALLOC_LEFT ++}; ++ ++#define SET_SSR_TYPE(type) (((type) + 1) << 16) ++#define GET_SSR_TYPE(type) (((type) >> 16) - 1) ++#define IS_SSR_TYPE(type) ((type) >= (0x1 << 16)) ++#define IS_NEXT_SEG(sbi, curseg, type) \ ++ (DIRTY_I(sbi)->v_ops->get_victim(sbi, &(curseg)->next_segno, \ ++ BG_GC, SET_SSR_TYPE(type))) ++/** ++ * The MSB 6 bits of f2fs_sit_entry->vblocks has segment type, ++ * and LSB 10 bits has valid blocks. ++ */ ++#define VBLOCKS_MASK ((1 << 10) - 1) ++ ++#define GET_SIT_VBLOCKS(raw_sit) \ ++ (le16_to_cpu((raw_sit)->vblocks) & VBLOCKS_MASK) ++#define GET_SIT_TYPE(raw_sit) \ ++ ((le16_to_cpu((raw_sit)->vblocks) & ~VBLOCKS_MASK) >> 10) ++ ++struct bio_private { ++ struct f2fs_sb_info *sbi; ++ bool is_sync; ++ void *wait; ++}; ++ ++enum { ++ GC_CB = 0, ++ GC_GREEDY ++}; ++ ++struct victim_sel_policy { ++ int alloc_mode; ++ int gc_mode; ++ int type; ++ unsigned long *dirty_segmap; ++ unsigned int offset; ++ unsigned int ofs_unit; ++ unsigned int min_cost; ++ unsigned int min_segno; ++}; ++ ++struct seg_entry { ++ unsigned short valid_blocks; ++ unsigned char *cur_valid_map; ++ unsigned short ckpt_valid_blocks; ++ unsigned char *ckpt_valid_map; ++ unsigned char type; ++ unsigned long long mtime; ++}; ++ ++struct sec_entry { ++ unsigned int valid_blocks; ++}; ++ ++struct segment_allocation { ++ void (*allocate_segment)(struct f2fs_sb_info *, int, bool); ++}; ++ ++struct sit_info { ++ const struct segment_allocation *s_ops; ++ ++ block_t sit_base_addr; ++ block_t sit_blocks; ++ block_t written_valid_blocks; /* total number of valid blocks ++ in main area */ ++ char *sit_bitmap; /* SIT bitmap pointer */ ++ unsigned int bitmap_size; ++ ++ unsigned int dirty_sentries; /* # of dirty sentries */ ++ unsigned long *dirty_sentries_bitmap; /* bitmap for dirty sentries */ ++ unsigned int sents_per_block; /* number of SIT entries ++ per SIT block */ ++ struct mutex sentry_lock; /* to protect SIT entries */ ++ struct seg_entry *sentries; ++ struct sec_entry *sec_entries; ++ ++ unsigned long long elapsed_time; ++ unsigned long long mounted_time; ++ unsigned long long min_mtime; ++ unsigned long long max_mtime; ++}; ++ ++struct free_segmap_info { ++ unsigned int start_segno; ++ unsigned int free_segments; ++ unsigned int free_sections; ++ rwlock_t segmap_lock; /* free segmap lock */ ++ unsigned long *free_segmap; ++ unsigned long *free_secmap; ++}; ++ ++/* Notice: The order of dirty type is same with CURSEG_XXX in f2fs.h */ ++enum dirty_type { ++ DIRTY_HOT_DATA, /* a few valid blocks in a data segment */ ++ DIRTY_WARM_DATA, ++ DIRTY_COLD_DATA, ++ DIRTY_HOT_NODE, /* a few valid blocks in a node segment */ ++ DIRTY_WARM_NODE, ++ DIRTY_COLD_NODE, ++ DIRTY, ++ PRE, /* no valid blocks in a segment */ ++ NR_DIRTY_TYPE ++}; ++ ++enum { ++ BG_GC, ++ FG_GC ++}; ++ ++struct dirty_seglist_info { ++ const struct victim_selection *v_ops; ++ struct mutex seglist_lock; ++ unsigned long *dirty_segmap[NR_DIRTY_TYPE]; ++ int nr_dirty[NR_DIRTY_TYPE]; ++ unsigned long *victim_segmap[2]; /* BG_GC, FG_GC */ ++}; ++ ++struct victim_selection { ++ int (*get_victim)(struct f2fs_sb_info *, unsigned int *, int, int); ++}; ++ ++struct curseg_info { ++ struct mutex curseg_mutex; ++ struct f2fs_summary_block *sum_blk; ++ unsigned char alloc_type; ++ unsigned int segno; ++ unsigned short next_blkoff; ++ unsigned int zone; ++ unsigned int next_segno; ++}; ++ ++/** ++ * inline functions ++ */ ++static inline struct curseg_info *CURSEG_I(struct f2fs_sb_info *sbi, int type) ++{ ++ return (struct curseg_info *)(SM_I(sbi)->curseg_array + type); ++} ++ ++static inline struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi, ++ unsigned int segno) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ return &sit_i->sentries[segno]; ++} ++ ++static inline struct sec_entry *get_sec_entry(struct f2fs_sb_info *sbi, ++ unsigned int segno) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ return &sit_i->sec_entries[GET_SECNO(sbi, segno)]; ++} ++ ++static inline unsigned int get_valid_blocks(struct f2fs_sb_info *sbi, ++ unsigned int segno, int section) ++{ ++ if (section > 1) ++ return get_sec_entry(sbi, segno)->valid_blocks; ++ else ++ return get_seg_entry(sbi, segno)->valid_blocks; ++} ++ ++static inline void seg_info_from_raw_sit(struct seg_entry *se, ++ struct f2fs_sit_entry *rs) ++{ ++ se->valid_blocks = GET_SIT_VBLOCKS(rs); ++ se->ckpt_valid_blocks = GET_SIT_VBLOCKS(rs); ++ memcpy(se->cur_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE); ++ memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE); ++ se->type = GET_SIT_TYPE(rs); ++ se->mtime = le64_to_cpu(rs->mtime); ++} ++ ++static inline void seg_info_to_raw_sit(struct seg_entry *se, ++ struct f2fs_sit_entry *rs) ++{ ++ unsigned short raw_vblocks = (se->type << 10) | se->valid_blocks; ++ rs->vblocks = cpu_to_le16(raw_vblocks); ++ memcpy(rs->valid_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE); ++ memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE); ++ se->ckpt_valid_blocks = se->valid_blocks; ++ rs->mtime = cpu_to_le64(se->mtime); ++} ++ ++static inline unsigned int find_next_inuse(struct free_segmap_info *free_i, ++ unsigned int max, unsigned int segno) ++{ ++ unsigned int ret; ++ read_lock(&free_i->segmap_lock); ++ ret = find_next_bit(free_i->free_segmap, max, segno); ++ read_unlock(&free_i->segmap_lock); ++ return ret; ++} ++ ++static inline void __set_free(struct f2fs_sb_info *sbi, unsigned int segno) ++{ ++ struct free_segmap_info *free_i = FREE_I(sbi); ++ unsigned int secno = segno / sbi->segs_per_sec; ++ unsigned int start_segno = secno * sbi->segs_per_sec; ++ unsigned int next; ++ ++ write_lock(&free_i->segmap_lock); ++ clear_bit(segno, free_i->free_segmap); ++ free_i->free_segments++; ++ ++ next = find_next_bit(free_i->free_segmap, TOTAL_SEGS(sbi), start_segno); ++ if (next >= start_segno + sbi->segs_per_sec) { ++ clear_bit(secno, free_i->free_secmap); ++ free_i->free_sections++; ++ } ++ write_unlock(&free_i->segmap_lock); ++} ++ ++static inline void __set_inuse(struct f2fs_sb_info *sbi, ++ unsigned int segno) ++{ ++ struct free_segmap_info *free_i = FREE_I(sbi); ++ unsigned int secno = segno / sbi->segs_per_sec; ++ set_bit(segno, free_i->free_segmap); ++ free_i->free_segments--; ++ if (!test_and_set_bit(secno, free_i->free_secmap)) ++ free_i->free_sections--; ++} ++ ++static inline void __set_test_and_free(struct f2fs_sb_info *sbi, ++ unsigned int segno) ++{ ++ struct free_segmap_info *free_i = FREE_I(sbi); ++ unsigned int secno = segno / sbi->segs_per_sec; ++ unsigned int start_segno = secno * sbi->segs_per_sec; ++ unsigned int next; ++ ++ write_lock(&free_i->segmap_lock); ++ if (test_and_clear_bit(segno, free_i->free_segmap)) { ++ free_i->free_segments++; ++ ++ next = find_next_bit(free_i->free_segmap, TOTAL_SEGS(sbi), ++ start_segno); ++ if (next >= start_segno + sbi->segs_per_sec) { ++ if (test_and_clear_bit(secno, free_i->free_secmap)) ++ free_i->free_sections++; ++ } ++ } ++ write_unlock(&free_i->segmap_lock); ++} ++ ++static inline void __set_test_and_inuse(struct f2fs_sb_info *sbi, ++ unsigned int segno) ++{ ++ struct free_segmap_info *free_i = FREE_I(sbi); ++ unsigned int secno = segno / sbi->segs_per_sec; ++ write_lock(&free_i->segmap_lock); ++ if (!test_and_set_bit(segno, free_i->free_segmap)) { ++ free_i->free_segments--; ++ if (!test_and_set_bit(secno, free_i->free_secmap)) ++ free_i->free_sections--; ++ } ++ write_unlock(&free_i->segmap_lock); ++} ++ ++static inline void get_sit_bitmap(struct f2fs_sb_info *sbi, ++ void *dst_addr) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ memcpy(dst_addr, sit_i->sit_bitmap, sit_i->bitmap_size); ++} ++ ++static inline block_t written_block_count(struct f2fs_sb_info *sbi) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ block_t vblocks; ++ ++ mutex_lock(&sit_i->sentry_lock); ++ vblocks = sit_i->written_valid_blocks; ++ mutex_unlock(&sit_i->sentry_lock); ++ ++ return vblocks; ++} ++ ++static inline unsigned int free_segments(struct f2fs_sb_info *sbi) ++{ ++ struct free_segmap_info *free_i = FREE_I(sbi); ++ unsigned int free_segs; ++ ++ read_lock(&free_i->segmap_lock); ++ free_segs = free_i->free_segments; ++ read_unlock(&free_i->segmap_lock); ++ ++ return free_segs; ++} ++ ++static inline int reserved_segments(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_gc_info *gc_i = sbi->gc_info; ++ return gc_i->rsvd_segment_count; ++} ++ ++static inline unsigned int free_sections(struct f2fs_sb_info *sbi) ++{ ++ struct free_segmap_info *free_i = FREE_I(sbi); ++ unsigned int free_secs; ++ ++ read_lock(&free_i->segmap_lock); ++ free_secs = free_i->free_sections; ++ read_unlock(&free_i->segmap_lock); ++ ++ return free_secs; ++} ++ ++static inline unsigned int prefree_segments(struct f2fs_sb_info *sbi) ++{ ++ return DIRTY_I(sbi)->nr_dirty[PRE]; ++} ++ ++static inline unsigned int dirty_segments(struct f2fs_sb_info *sbi) ++{ ++ return DIRTY_I(sbi)->nr_dirty[DIRTY_HOT_DATA] + ++ DIRTY_I(sbi)->nr_dirty[DIRTY_WARM_DATA] + ++ DIRTY_I(sbi)->nr_dirty[DIRTY_COLD_DATA] + ++ DIRTY_I(sbi)->nr_dirty[DIRTY_HOT_NODE] + ++ DIRTY_I(sbi)->nr_dirty[DIRTY_WARM_NODE] + ++ DIRTY_I(sbi)->nr_dirty[DIRTY_COLD_NODE]; ++} ++ ++static inline int overprovision_segments(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_gc_info *gc_i = sbi->gc_info; ++ return gc_i->overp_segment_count; ++} ++ ++static inline int overprovision_sections(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_gc_info *gc_i = sbi->gc_info; ++ return ((unsigned int) gc_i->overp_segment_count) / sbi->segs_per_sec; ++} ++ ++static inline int reserved_sections(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_gc_info *gc_i = sbi->gc_info; ++ return ((unsigned int) gc_i->rsvd_segment_count) / sbi->segs_per_sec; ++} ++ ++static inline bool need_SSR(struct f2fs_sb_info *sbi) ++{ ++ return (free_sections(sbi) < overprovision_sections(sbi)); ++} ++ ++static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi) ++{ ++ return free_sections(sbi) <= reserved_sections(sbi); ++} ++ ++static inline int utilization(struct f2fs_sb_info *sbi) ++{ ++ return (long int)valid_user_blocks(sbi) * 100 / ++ (long int)sbi->user_block_count; ++} ++ ++/* Disable In-Place-Update by default */ ++#define MIN_IPU_UTIL 100 ++static inline bool need_inplace_update(struct inode *inode) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ if (S_ISDIR(inode->i_mode)) ++ return false; ++ if (need_SSR(sbi) && utilization(sbi) > MIN_IPU_UTIL) ++ return true; ++ return false; ++} ++ ++static inline unsigned int curseg_segno(struct f2fs_sb_info *sbi, ++ int type) ++{ ++ struct curseg_info *curseg = CURSEG_I(sbi, type); ++ return curseg->segno; ++} ++ ++static inline unsigned char curseg_alloc_type(struct f2fs_sb_info *sbi, ++ int type) ++{ ++ struct curseg_info *curseg = CURSEG_I(sbi, type); ++ return curseg->alloc_type; ++} ++ ++static inline unsigned short curseg_blkoff(struct f2fs_sb_info *sbi, int type) ++{ ++ struct curseg_info *curseg = CURSEG_I(sbi, type); ++ return curseg->next_blkoff; ++} ++ ++static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) ++{ ++ unsigned int end_segno = SM_I(sbi)->segment_count - 1; ++ BUG_ON(segno > end_segno); ++} ++ ++/* ++ * This function is used for only debugging. ++ * NOTE: In future, we have to remove this function. ++ */ ++static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr) ++{ ++ struct f2fs_sm_info *sm_info = SM_I(sbi); ++ block_t total_blks = sm_info->segment_count << sbi->log_blocks_per_seg; ++ block_t start_addr = sm_info->seg0_blkaddr; ++ block_t end_addr = start_addr + total_blks - 1; ++ BUG_ON(blk_addr < start_addr); ++ BUG_ON(blk_addr > end_addr); ++} ++ ++/** ++ * Summary block is always treated as invalid block ++ */ ++static inline void check_block_count(struct f2fs_sb_info *sbi, ++ int segno, struct f2fs_sit_entry *raw_sit) ++{ ++ struct f2fs_sm_info *sm_info = SM_I(sbi); ++ unsigned int end_segno = sm_info->segment_count - 1; ++ int valid_blocks = 0; ++ int i; ++ ++ /* check segment usage */ ++ BUG_ON(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg); ++ ++ /* check boundary of a given segment number */ ++ BUG_ON(segno > end_segno); ++ ++ /* check bitmap with valid block count */ ++ for (i = 0; i < sbi->blocks_per_seg; i++) ++ if (f2fs_test_bit(i, raw_sit->valid_map)) ++ valid_blocks++; ++ BUG_ON(GET_SIT_VBLOCKS(raw_sit) != valid_blocks); ++} ++ ++static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi, ++ unsigned int start) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ unsigned int offset = SIT_BLOCK_OFFSET(sit_i, start); ++ block_t blk_addr = sit_i->sit_base_addr + offset; ++ ++ check_seg_range(sbi, start); ++ ++ /* calculate sit block address */ ++ if (f2fs_test_bit(offset, sit_i->sit_bitmap)) ++ blk_addr += sit_i->sit_blocks; ++ ++ return blk_addr; ++} ++ ++static inline pgoff_t next_sit_addr(struct f2fs_sb_info *sbi, ++ pgoff_t block_addr) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ block_addr -= sit_i->sit_base_addr; ++ if (block_addr < sit_i->sit_blocks) ++ block_addr += sit_i->sit_blocks; ++ else ++ block_addr -= sit_i->sit_blocks; ++ ++ return block_addr + sit_i->sit_base_addr; ++} ++ ++static inline void set_to_next_sit(struct sit_info *sit_i, unsigned int start) ++{ ++ unsigned int block_off = SIT_BLOCK_OFFSET(sit_i, start); ++ ++ if (f2fs_test_bit(block_off, sit_i->sit_bitmap)) ++ f2fs_clear_bit(block_off, sit_i->sit_bitmap); ++ else ++ f2fs_set_bit(block_off, sit_i->sit_bitmap); ++} ++ ++static inline unsigned long long get_mtime(struct f2fs_sb_info *sbi) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ return sit_i->elapsed_time + CURRENT_TIME_SEC.tv_sec - ++ sit_i->mounted_time; ++} ++ ++static inline void set_summary(struct f2fs_summary *sum, nid_t nid, ++ unsigned int ofs_in_node, unsigned char version) ++{ ++ sum->nid = cpu_to_le32(nid); ++ sum->ofs_in_node = cpu_to_le16(ofs_in_node); ++ sum->version = version; ++} ++ ++static inline block_t start_sum_block(struct f2fs_sb_info *sbi) ++{ ++ return __start_cp_addr(sbi) + ++ le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum); ++} ++ ++static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type) ++{ ++ return __start_cp_addr(sbi) + ++ le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_total_block_count) ++ - (base + 1) + type; ++} diff --git a/patches/linux-3.7-rc6/0101-f2fs-add-super-block-operations.patch b/patches/linux-3.7-rc6/0101-f2fs-add-super-block-operations.patch new file mode 100644 index 0000000..84e9529 --- /dev/null +++ b/patches/linux-3.7-rc6/0101-f2fs-add-super-block-operations.patch @@ -0,0 +1,612 @@ +From b75928193c6e929da5808d20204910c4c7b4eed7 Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:27:13 +0000 +Subject: [PATCH] f2fs: add super block operations + +This adds the implementation of superblock operations for f2fs, which includes +- init_f2fs_fs/exit_f2fs_fs +- f2fs_mount +- super_operations of f2fs + +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/f2fs/super.c | 590 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 590 insertions(+) + create mode 100644 fs/f2fs/super.c + +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +new file mode 100644 +index 0000000..8e608a0 +--- /dev/null ++++ b/fs/f2fs/super.c +@@ -0,0 +1,590 @@ ++/** ++ * fs/f2fs/super.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/statfs.h> ++#include <linux/proc_fs.h> ++#include <linux/buffer_head.h> ++#include <linux/backing-dev.h> ++#include <linux/kthread.h> ++#include <linux/parser.h> ++#include <linux/mount.h> ++#include <linux/seq_file.h> ++#include <linux/f2fs_fs.h> ++ ++#include "f2fs.h" ++#include "node.h" ++#include "xattr.h" ++ ++static struct kmem_cache *f2fs_inode_cachep; ++static struct proc_dir_entry *f2fs_proc_root; ++ ++enum { ++ Opt_gc_background_off, ++ Opt_disable_roll_forward, ++ Opt_discard, ++ Opt_noheap, ++ Opt_nouser_xattr, ++ Opt_noacl, ++ Opt_active_logs, ++ Opt_disable_ext_identify, ++ Opt_err, ++}; ++ ++static match_table_t f2fs_tokens = { ++ {Opt_gc_background_off, "background_gc_off"}, ++ {Opt_disable_roll_forward, "disable_roll_forward"}, ++ {Opt_discard, "discard"}, ++ {Opt_noheap, "no_heap"}, ++ {Opt_nouser_xattr, "nouser_xattr"}, ++ {Opt_noacl, "noacl"}, ++ {Opt_active_logs, "active_logs=%u"}, ++ {Opt_disable_ext_identify, "disable_ext_identify"}, ++ {Opt_err, NULL}, ++}; ++ ++static void init_once(void *foo) ++{ ++ struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo; ++ ++ memset(fi, 0, sizeof(*fi)); ++ inode_init_once(&fi->vfs_inode); ++} ++ ++static struct inode *f2fs_alloc_inode(struct super_block *sb) ++{ ++ struct f2fs_inode_info *fi; ++ ++ fi = kmem_cache_alloc(f2fs_inode_cachep, GFP_NOFS | __GFP_ZERO); ++ if (!fi) ++ return NULL; ++ ++ init_once((void *) fi); ++ ++ /* Initilize f2fs-specific inode info */ ++ fi->vfs_inode.i_version = 1; ++ atomic_set(&fi->dirty_dents, 0); ++ fi->current_depth = 1; ++ fi->i_advise = 0; ++ rwlock_init(&fi->ext.ext_lock); ++ ++ set_inode_flag(fi, FI_NEW_INODE); ++ ++ return &fi->vfs_inode; ++} ++ ++static void f2fs_i_callback(struct rcu_head *head) ++{ ++ struct inode *inode = container_of(head, struct inode, i_rcu); ++ kmem_cache_free(f2fs_inode_cachep, F2FS_I(inode)); ++} ++ ++void f2fs_destroy_inode(struct inode *inode) ++{ ++ call_rcu(&inode->i_rcu, f2fs_i_callback); ++} ++ ++static void f2fs_put_super(struct super_block *sb) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(sb); ++ ++#ifdef CONFIG_F2FS_STAT_FS ++ if (sbi->s_proc) { ++ f2fs_stat_exit(sbi); ++ remove_proc_entry(sb->s_id, f2fs_proc_root); ++ } ++#endif ++ stop_gc_thread(sbi); ++ ++ write_checkpoint(sbi, false, true); ++ ++ iput(sbi->node_inode); ++ iput(sbi->meta_inode); ++ ++ /* destroy f2fs internal modules */ ++ destroy_gc_manager(sbi); ++ destroy_node_manager(sbi); ++ destroy_segment_manager(sbi); ++ ++ kfree(sbi->ckpt); ++ ++ sb->s_fs_info = NULL; ++ brelse(sbi->raw_super_buf); ++ kfree(sbi); ++} ++ ++int f2fs_sync_fs(struct super_block *sb, int sync) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(sb); ++ int ret = 0; ++ ++ if (!sbi->s_dirty && !get_pages(sbi, F2FS_DIRTY_NODES)) ++ return 0; ++ ++ if (sync) ++ write_checkpoint(sbi, false, false); ++ ++ return ret; ++} ++ ++static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ struct super_block *sb = dentry->d_sb; ++ struct f2fs_sb_info *sbi = F2FS_SB(sb); ++ block_t total_count, user_block_count, start_count, ovp_count; ++ ++ total_count = le64_to_cpu(sbi->raw_super->block_count); ++ user_block_count = sbi->user_block_count; ++ start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr); ++ ovp_count = sbi->gc_info->overp_segment_count ++ << sbi->log_blocks_per_seg; ++ buf->f_type = F2FS_SUPER_MAGIC; ++ buf->f_bsize = sbi->blocksize; ++ ++ buf->f_blocks = total_count - start_count; ++ buf->f_bfree = buf->f_blocks - valid_user_blocks(sbi) - ovp_count; ++ buf->f_bavail = user_block_count - valid_user_blocks(sbi); ++ ++ buf->f_files = valid_inode_count(sbi); ++ buf->f_ffree = sbi->total_node_count - valid_node_count(sbi); ++ ++ buf->f_namelen = F2FS_MAX_NAME_LEN; ++ ++ return 0; ++} ++ ++static int f2fs_show_options(struct seq_file *seq, struct dentry *root) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb); ++ ++ if (test_opt(sbi, BG_GC)) ++ seq_puts(seq, ",background_gc_on"); ++ else ++ seq_puts(seq, ",background_gc_off"); ++ if (test_opt(sbi, DISABLE_ROLL_FORWARD)) ++ seq_puts(seq, ",disable_roll_forward"); ++ if (test_opt(sbi, DISCARD)) ++ seq_puts(seq, ",discard"); ++ if (test_opt(sbi, NOHEAP)) ++ seq_puts(seq, ",no_heap_alloc"); ++#ifdef CONFIG_F2FS_FS_XATTR ++ if (test_opt(sbi, XATTR_USER)) ++ seq_puts(seq, ",user_xattr"); ++ else ++ seq_puts(seq, ",nouser_xattr"); ++#endif ++#ifdef CONFIG_F2FS_FS_POSIX_ACL ++ if (test_opt(sbi, POSIX_ACL)) ++ seq_puts(seq, ",acl"); ++ else ++ seq_puts(seq, ",noacl"); ++#endif ++ if (test_opt(sbi, DISABLE_EXT_IDENTIFY)) ++ seq_puts(seq, ",disable_ext_indentify"); ++ ++ seq_printf(seq, ",active_logs=%u", sbi->active_logs); ++ ++ return 0; ++} ++ ++static struct super_operations f2fs_sops = { ++ .alloc_inode = f2fs_alloc_inode, ++ .destroy_inode = f2fs_destroy_inode, ++ .write_inode = f2fs_write_inode, ++ .show_options = f2fs_show_options, ++ .evict_inode = f2fs_evict_inode, ++ .put_super = f2fs_put_super, ++ .sync_fs = f2fs_sync_fs, ++ .statfs = f2fs_statfs, ++}; ++ ++static int parse_options(struct f2fs_sb_info *sbi, char *options) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ char *p; ++ int arg = 0; ++ ++ if (!options) ++ return 0; ++ ++ while ((p = strsep(&options, ",")) != NULL) { ++ int token; ++ if (!*p) ++ continue; ++ /* ++ * Initialize args struct so we know whether arg was ++ * found; some options take optional arguments. ++ */ ++ args[0].to = args[0].from = NULL; ++ token = match_token(p, f2fs_tokens, args); ++ ++ switch (token) { ++ case Opt_gc_background_off: ++ clear_opt(sbi, BG_GC); ++ break; ++ case Opt_disable_roll_forward: ++ set_opt(sbi, DISABLE_ROLL_FORWARD); ++ break; ++ case Opt_discard: ++ set_opt(sbi, DISCARD); ++ break; ++ case Opt_noheap: ++ set_opt(sbi, NOHEAP); ++ break; ++#ifdef CONFIG_F2FS_FS_XATTR ++ case Opt_nouser_xattr: ++ clear_opt(sbi, XATTR_USER); ++ break; ++#else ++ case Opt_nouser_xattr: ++ pr_info("nouser_xattr options not supported\n"); ++ break; ++#endif ++#ifdef CONFIG_F2FS_FS_POSIX_ACL ++ case Opt_noacl: ++ clear_opt(sbi, POSIX_ACL); ++ break; ++#else ++ case Opt_noacl: ++ pr_info("noacl options not supported\n"); ++ break; ++#endif ++ case Opt_active_logs: ++ if (args->from && match_int(args, &arg)) ++ return -EINVAL; ++ if (arg != 2 && arg != 4 && arg != 6) ++ return -EINVAL; ++ sbi->active_logs = arg; ++ break; ++ case Opt_disable_ext_identify: ++ set_opt(sbi, DISABLE_EXT_IDENTIFY); ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ return 0; ++} ++ ++static loff_t max_file_size(unsigned bits) ++{ ++ loff_t result = ADDRS_PER_INODE; ++ loff_t leaf_count = ADDRS_PER_BLOCK; ++ ++ result += (leaf_count * 2); ++ ++ leaf_count *= NIDS_PER_BLOCK; ++ result += (leaf_count * 2); ++ ++ leaf_count *= NIDS_PER_BLOCK; ++ result += (leaf_count * 2); ++ ++ result <<= bits; ++ return result; ++} ++ ++static int sanity_check_raw_super(struct f2fs_super_block *raw_super) ++{ ++ unsigned int blocksize; ++ ++ if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) ++ return 1; ++ ++ /* Currently, support only 4KB block size */ ++ blocksize = 1 << le32_to_cpu(raw_super->log_blocksize); ++ if (blocksize != PAGE_CACHE_SIZE) ++ return 1; ++ if (le32_to_cpu(raw_super->log_sectorsize) != 9) ++ return 1; ++ if (le32_to_cpu(raw_super->log_sectors_per_block) != 3) ++ return 1; ++ return 0; ++} ++ ++static int sanity_check_ckpt(struct f2fs_super_block *raw_super, ++ struct f2fs_checkpoint *ckpt) ++{ ++ unsigned int total, fsmeta; ++ ++ total = le32_to_cpu(raw_super->segment_count); ++ fsmeta = le32_to_cpu(raw_super->segment_count_ckpt); ++ fsmeta += le32_to_cpu(raw_super->segment_count_sit); ++ fsmeta += le32_to_cpu(raw_super->segment_count_nat); ++ fsmeta += le32_to_cpu(ckpt->rsvd_segment_count); ++ fsmeta += le32_to_cpu(raw_super->segment_count_ssa); ++ ++ if (fsmeta >= total) ++ return 1; ++ return 0; ++} ++ ++static void init_sb_info(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_super_block *raw_super = sbi->raw_super; ++ int i; ++ ++ sbi->log_sectorsize = le32_to_cpu(raw_super->log_sectorsize); ++ sbi->log_sectors_per_block = ++ le32_to_cpu(raw_super->log_sectors_per_block); ++ sbi->log_blocksize = le32_to_cpu(raw_super->log_blocksize); ++ sbi->blocksize = 1 << sbi->log_blocksize; ++ sbi->log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); ++ sbi->blocks_per_seg = 1 << sbi->log_blocks_per_seg; ++ sbi->segs_per_sec = le32_to_cpu(raw_super->segs_per_sec); ++ sbi->secs_per_zone = le32_to_cpu(raw_super->secs_per_zone); ++ sbi->total_sections = le32_to_cpu(raw_super->section_count); ++ sbi->total_node_count = ++ (le32_to_cpu(raw_super->segment_count_nat) / 2) ++ * sbi->blocks_per_seg * NAT_ENTRY_PER_BLOCK; ++ sbi->root_ino_num = le32_to_cpu(raw_super->root_ino); ++ sbi->node_ino_num = le32_to_cpu(raw_super->node_ino); ++ sbi->meta_ino_num = le32_to_cpu(raw_super->meta_ino); ++ ++ for (i = 0; i < NR_COUNT_TYPE; i++) ++ atomic_set(&sbi->nr_pages[i], 0); ++} ++ ++static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ++{ ++ struct f2fs_sb_info *sbi; ++ struct f2fs_super_block *raw_super; ++ struct buffer_head *raw_super_buf; ++ struct inode *root; ++ int i; ++ ++ /* allocate memory for f2fs-specific super block info */ ++ sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL); ++ if (!sbi) ++ return -ENOMEM; ++ ++ /* set a temporary block size */ ++ if (!sb_set_blocksize(sb, F2FS_BLKSIZE)) ++ goto free_sbi; ++ ++ /* read f2fs raw super block */ ++ raw_super_buf = sb_bread(sb, F2FS_SUPER_OFFSET); ++ if (!raw_super_buf) ++ goto free_sbi; ++ raw_super = (struct f2fs_super_block *) ((char *)raw_super_buf->b_data); ++ ++ /* init some FS parameters */ ++ sbi->active_logs = NR_CURSEG_TYPE; ++ ++ set_opt(sbi, BG_GC); ++ ++#ifdef CONFIG_F2FS_FS_XATTR ++ set_opt(sbi, XATTR_USER); ++#endif ++#ifdef CONFIG_F2FS_FS_POSIX_ACL ++ set_opt(sbi, POSIX_ACL); ++#endif ++ /* parse mount options */ ++ if (parse_options(sbi, (char *)data)) ++ goto free_sb_buf; ++ ++ /* sanity checking of raw super */ ++ if (sanity_check_raw_super(raw_super)) ++ goto free_sb_buf; ++ ++ sb->s_maxbytes = max_file_size(raw_super->log_blocksize); ++ sb->s_max_links = F2FS_LINK_MAX; ++ ++ sb->s_op = &f2fs_sops; ++ sb->s_xattr = f2fs_xattr_handlers; ++ sb->s_magic = F2FS_SUPER_MAGIC; ++ sb->s_fs_info = sbi; ++ sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ++ (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0); ++ ++ /* init f2fs-specific super block info */ ++ sbi->sb = sb; ++ sbi->raw_super = raw_super; ++ sbi->raw_super_buf = raw_super_buf; ++ mutex_init(&sbi->gc_mutex); ++ mutex_init(&sbi->write_inode); ++ mutex_init(&sbi->writepages); ++ mutex_init(&sbi->cp_mutex); ++ for (i = 0; i < NR_LOCK_TYPE; i++) ++ mutex_init(&sbi->fs_lock[i]); ++ sbi->por_doing = 0; ++ spin_lock_init(&sbi->stat_lock); ++ init_rwsem(&sbi->bio_sem); ++ init_sb_info(sbi); ++ ++ /* get an inode for meta space */ ++ sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi)); ++ if (IS_ERR(sbi->meta_inode)) ++ goto free_sb_buf; ++ ++ if (get_valid_checkpoint(sbi)) ++ goto free_meta_inode; ++ ++ /* sanity checking of checkpoint */ ++ if (sanity_check_ckpt(raw_super, sbi->ckpt)) ++ goto free_cp; ++ ++ sbi->total_valid_node_count = ++ le32_to_cpu(sbi->ckpt->valid_node_count); ++ sbi->total_valid_inode_count = ++ le32_to_cpu(sbi->ckpt->valid_inode_count); ++ sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count); ++ sbi->total_valid_block_count = ++ le64_to_cpu(sbi->ckpt->valid_block_count); ++ sbi->last_valid_block_count = sbi->total_valid_block_count; ++ sbi->alloc_valid_block_count = 0; ++ INIT_LIST_HEAD(&sbi->dir_inode_list); ++ spin_lock_init(&sbi->dir_inode_lock); ++ ++ /* init super block */ ++ if (!sb_set_blocksize(sb, sbi->blocksize)) ++ goto free_cp; ++ ++ init_orphan_info(sbi); ++ ++ /* setup f2fs internal modules */ ++ if (build_segment_manager(sbi)) ++ goto free_sm; ++ if (build_node_manager(sbi)) ++ goto free_nm; ++ if (build_gc_manager(sbi)) ++ goto free_gc; ++ ++ /* get an inode for node space */ ++ sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi)); ++ if (IS_ERR(sbi->node_inode)) ++ goto free_gc; ++ ++ /* if there are nt orphan nodes free them */ ++ if (recover_orphan_inodes(sbi)) ++ goto free_node_inode; ++ ++ /* read root inode and dentry */ ++ root = f2fs_iget(sb, F2FS_ROOT_INO(sbi)); ++ if (IS_ERR(root)) ++ goto free_node_inode; ++ if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) ++ goto free_root_inode; ++ ++ sb->s_root = d_make_root(root); /* allocate root dentry */ ++ if (!sb->s_root) ++ goto free_root_inode; ++ ++ /* recover fsynced data */ ++ if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) ++ recover_fsync_data(sbi); ++ ++ /* After POR, we can run background GC thread */ ++ if (start_gc_thread(sbi)) ++ goto fail; ++ ++#ifdef CONFIG_F2FS_STAT_FS ++ if (f2fs_proc_root) { ++ sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); ++ if (f2fs_stat_init(sbi)) ++ goto fail; ++ } ++#endif ++ return 0; ++fail: ++ stop_gc_thread(sbi); ++free_root_inode: ++ make_bad_inode(root); ++ iput(root); ++free_node_inode: ++ make_bad_inode(sbi->node_inode); ++ iput(sbi->node_inode); ++free_gc: ++ destroy_gc_manager(sbi); ++free_nm: ++ destroy_node_manager(sbi); ++free_sm: ++ destroy_segment_manager(sbi); ++free_cp: ++ kfree(sbi->ckpt); ++free_meta_inode: ++ make_bad_inode(sbi->meta_inode); ++ iput(sbi->meta_inode); ++free_sb_buf: ++ brelse(raw_super_buf); ++free_sbi: ++ kfree(sbi); ++ return -EINVAL; ++} ++ ++static struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags, ++ const char *dev_name, void *data) ++{ ++ return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super); ++} ++ ++static struct file_system_type f2fs_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "f2fs", ++ .mount = f2fs_mount, ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV, ++}; ++ ++static int init_inodecache(void) ++{ ++ f2fs_inode_cachep = f2fs_kmem_cache_create("f2fs_inode_cache", ++ sizeof(struct f2fs_inode_info), NULL); ++ if (f2fs_inode_cachep == NULL) ++ return -ENOMEM; ++ return 0; ++} ++ ++static void destroy_inodecache(void) ++{ ++ /* ++ * Make sure all delayed rcu free inodes are flushed before we ++ * destroy cache. ++ */ ++ rcu_barrier(); ++ kmem_cache_destroy(f2fs_inode_cachep); ++} ++ ++static int __init init_f2fs_fs(void) ++{ ++ if (init_inodecache()) ++ goto fail; ++ if (create_node_manager_caches()) ++ goto fail; ++ if (create_gc_caches()) ++ goto fail; ++ if (create_checkpoint_caches()) ++ goto fail; ++ if (register_filesystem(&f2fs_fs_type)) ++ return -EBUSY; ++ ++ f2fs_proc_root = proc_mkdir("fs/f2fs", NULL); ++ return 0; ++fail: ++ return -ENOMEM; ++} ++ ++static void __exit exit_f2fs_fs(void) ++{ ++ remove_proc_entry("fs/f2fs", NULL); ++ unregister_filesystem(&f2fs_fs_type); ++ destroy_checkpoint_caches(); ++ destroy_gc_caches(); ++ destroy_node_manager_caches(); ++ destroy_inodecache(); ++} ++ ++module_init(init_f2fs_fs) ++module_exit(exit_f2fs_fs) ++ ++MODULE_AUTHOR("Samsung Electronics's Praesto Team"); ++MODULE_DESCRIPTION("Flash Friendly File System"); ++MODULE_LICENSE("GPL"); diff --git a/patches/linux-3.7-rc6/0102-f2fs-add-checkpoint-operations.patch b/patches/linux-3.7-rc6/0102-f2fs-add-checkpoint-operations.patch new file mode 100644 index 0000000..7da534b --- /dev/null +++ b/patches/linux-3.7-rc6/0102-f2fs-add-checkpoint-operations.patch @@ -0,0 +1,834 @@ +From d7db5b2e4d88ad2fa8f6d03c653e081593e8602d Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:28:03 +0000 +Subject: [PATCH] f2fs: add checkpoint operations + +This adds functions required by the checkpoint operations. + +Basically, f2fs adopts a roll-back model with checkpoint blocks written in the +CP area. The checkpoint procedure includes as follows. + +- write_checkpoint() +1. block_operations() freezes VFS calls. +2. submit cached bios. +3. flush_nat_entries() writes NAT pages updated by dirty NAT entries. +4. flush_sit_entries() writes SIT pages updated by dirty SIT entries. +5. do_checkpoint() writes, + - checkpoint block (#0) + - orphan inode blocks + - summary blocks made by active logs + - checkpoint block (copy of #0) +6. unblock_opeations() + +In order to provide an address space for meta pages, f2fs_sb_info has a special +inode, namely meta_inode. This patch also adds the address space operations for +meta_inode. + +Signed-off-by: Chul Lee <chur.lee@samsung.com> +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/f2fs/checkpoint.c | 795 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 795 insertions(+) + create mode 100644 fs/f2fs/checkpoint.c + +diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c +new file mode 100644 +index 0000000..a0601cc +--- /dev/null ++++ b/fs/f2fs/checkpoint.c +@@ -0,0 +1,795 @@ ++/** ++ * fs/f2fs/checkpoint.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/fs.h> ++#include <linux/bio.h> ++#include <linux/mpage.h> ++#include <linux/writeback.h> ++#include <linux/blkdev.h> ++#include <linux/f2fs_fs.h> ++#include <linux/pagevec.h> ++#include <linux/swap.h> ++ ++#include "f2fs.h" ++#include "node.h" ++#include "segment.h" ++ ++static struct kmem_cache *orphan_entry_slab; ++static struct kmem_cache *inode_entry_slab; ++ ++/** ++ * We guarantee no failure on the returned page. ++ */ ++struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) ++{ ++ struct address_space *mapping = sbi->meta_inode->i_mapping; ++ struct page *page = NULL; ++repeat: ++ page = grab_cache_page(mapping, index); ++ if (!page) { ++ cond_resched(); ++ goto repeat; ++ } ++ ++ /* We wait writeback only inside grab_meta_page() */ ++ wait_on_page_writeback(page); ++ SetPageUptodate(page); ++ return page; ++} ++ ++/** ++ * We guarantee no failure on the returned page. ++ */ ++struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) ++{ ++ struct address_space *mapping = sbi->meta_inode->i_mapping; ++ struct page *page; ++repeat: ++ page = grab_cache_page(mapping, index); ++ if (!page) { ++ cond_resched(); ++ goto repeat; ++ } ++ if (f2fs_readpage(sbi, page, index, READ_SYNC)) { ++ f2fs_put_page(page, 1); ++ goto repeat; ++ } ++ mark_page_accessed(page); ++ ++ /* We do not allow returning an errorneous page */ ++ return page; ++} ++ ++static int f2fs_write_meta_page(struct page *page, ++ struct writeback_control *wbc) ++{ ++ struct inode *inode = page->mapping->host; ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ int err; ++ ++ wait_on_page_writeback(page); ++ ++ err = write_meta_page(sbi, page, wbc); ++ if (err) { ++ wbc->pages_skipped++; ++ set_page_dirty(page); ++ } ++ ++ dec_page_count(sbi, F2FS_DIRTY_META); ++ ++ /* In this case, we should not unlock this page */ ++ if (err != AOP_WRITEPAGE_ACTIVATE) ++ unlock_page(page); ++ return err; ++} ++ ++static int f2fs_write_meta_pages(struct address_space *mapping, ++ struct writeback_control *wbc) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); ++ struct block_device *bdev = sbi->sb->s_bdev; ++ long written; ++ ++ if (wbc->for_kupdate) ++ return 0; ++ ++ if (get_pages(sbi, F2FS_DIRTY_META) == 0) ++ return 0; ++ ++ /* if mounting is failed, skip writing node pages */ ++ mutex_lock(&sbi->cp_mutex); ++ written = sync_meta_pages(sbi, META, bio_get_nr_vecs(bdev)); ++ mutex_unlock(&sbi->cp_mutex); ++ wbc->nr_to_write -= written; ++ return 0; ++} ++ ++long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, ++ long nr_to_write) ++{ ++ struct address_space *mapping = sbi->meta_inode->i_mapping; ++ pgoff_t index = 0, end = LONG_MAX; ++ struct pagevec pvec; ++ long nwritten = 0; ++ struct writeback_control wbc = { ++ .for_reclaim = 0, ++ }; ++ ++ pagevec_init(&pvec, 0); ++ ++ while (index <= end) { ++ int i, nr_pages; ++ nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, ++ PAGECACHE_TAG_DIRTY, ++ min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); ++ if (nr_pages == 0) ++ break; ++ ++ for (i = 0; i < nr_pages; i++) { ++ struct page *page = pvec.pages[i]; ++ lock_page(page); ++ BUG_ON(page->mapping != mapping); ++ BUG_ON(!PageDirty(page)); ++ clear_page_dirty_for_io(page); ++ f2fs_write_meta_page(page, &wbc); ++ if (nwritten++ >= nr_to_write) ++ break; ++ } ++ pagevec_release(&pvec); ++ cond_resched(); ++ } ++ ++ if (nwritten) ++ f2fs_submit_bio(sbi, type, nr_to_write == LONG_MAX); ++ ++ return nwritten; ++} ++ ++static int f2fs_set_meta_page_dirty(struct page *page) ++{ ++ struct address_space *mapping = page->mapping; ++ struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); ++ ++ SetPageUptodate(page); ++ if (!PageDirty(page)) { ++ __set_page_dirty_nobuffers(page); ++ inc_page_count(sbi, F2FS_DIRTY_META); ++ F2FS_SET_SB_DIRT(sbi); ++ return 1; ++ } ++ return 0; ++} ++ ++const struct address_space_operations f2fs_meta_aops = { ++ .writepage = f2fs_write_meta_page, ++ .writepages = f2fs_write_meta_pages, ++ .set_page_dirty = f2fs_set_meta_page_dirty, ++}; ++ ++int check_orphan_space(struct f2fs_sb_info *sbi) ++{ ++ unsigned int max_orphans; ++ int err = 0; ++ ++ /* ++ * considering 512 blocks in a segment 5 blocks are needed for cp ++ * and log segment summaries. Remaining blocks are used to keep ++ * orphan entries with the limitation one reserved segment ++ * for cp pack we can have max 1020*507 orphan entries ++ */ ++ max_orphans = (sbi->blocks_per_seg - 5) * F2FS_ORPHANS_PER_BLOCK; ++ mutex_lock(&sbi->orphan_inode_mutex); ++ if (sbi->n_orphans >= max_orphans) ++ err = -ENOSPC; ++ mutex_unlock(&sbi->orphan_inode_mutex); ++ return err; ++} ++ ++void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) ++{ ++ struct list_head *head, *this; ++ struct orphan_inode_entry *new = NULL, *orphan = NULL; ++ ++ mutex_lock(&sbi->orphan_inode_mutex); ++ head = &sbi->orphan_inode_list; ++ list_for_each(this, head) { ++ orphan = list_entry(this, struct orphan_inode_entry, list); ++ if (orphan->ino == ino) ++ goto out; ++ if (orphan->ino > ino) ++ break; ++ orphan = NULL; ++ } ++retry: ++ new = kmem_cache_alloc(orphan_entry_slab, GFP_ATOMIC); ++ if (!new) { ++ cond_resched(); ++ goto retry; ++ } ++ new->ino = ino; ++ INIT_LIST_HEAD(&new->list); ++ ++ /* add new_oentry into list which is sorted by inode number */ ++ if (orphan) { ++ struct orphan_inode_entry *prev; ++ ++ /* get previous entry */ ++ prev = list_entry(orphan->list.prev, typeof(*prev), list); ++ if (&prev->list != head) ++ /* insert new orphan inode entry */ ++ list_add(&new->list, &prev->list); ++ else ++ list_add(&new->list, head); ++ } else { ++ list_add_tail(&new->list, head); ++ } ++ sbi->n_orphans++; ++out: ++ mutex_unlock(&sbi->orphan_inode_mutex); ++} ++ ++void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) ++{ ++ struct list_head *this, *next, *head; ++ struct orphan_inode_entry *orphan; ++ ++ mutex_lock(&sbi->orphan_inode_mutex); ++ head = &sbi->orphan_inode_list; ++ list_for_each_safe(this, next, head) { ++ orphan = list_entry(this, struct orphan_inode_entry, list); ++ if (orphan->ino == ino) { ++ list_del(&orphan->list); ++ kmem_cache_free(orphan_entry_slab, orphan); ++ sbi->n_orphans--; ++ break; ++ } ++ } ++ mutex_unlock(&sbi->orphan_inode_mutex); ++} ++ ++static void recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) ++{ ++ struct inode *inode = f2fs_iget(sbi->sb, ino); ++ BUG_ON(IS_ERR(inode)); ++ clear_nlink(inode); ++ ++ /* truncate all the data during iput */ ++ iput(inode); ++} ++ ++int recover_orphan_inodes(struct f2fs_sb_info *sbi) ++{ ++ block_t start_blk, orphan_blkaddr, i, j; ++ ++ if (!(F2FS_CKPT(sbi)->ckpt_flags & CP_ORPHAN_PRESENT_FLAG)) ++ return 0; ++ ++ sbi->por_doing = 1; ++ start_blk = __start_cp_addr(sbi) + 1; ++ orphan_blkaddr = __start_sum_addr(sbi) - 1; ++ ++ for (i = 0; i < orphan_blkaddr; i++) { ++ struct page *page = get_meta_page(sbi, start_blk + i); ++ struct f2fs_orphan_block *orphan_blk; ++ ++ orphan_blk = (struct f2fs_orphan_block *)page_address(page); ++ for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) { ++ nid_t ino = le32_to_cpu(orphan_blk->ino[j]); ++ recover_orphan_inode(sbi, ino); ++ } ++ f2fs_put_page(page, 1); ++ } ++ /* clear Orphan Flag */ ++ F2FS_CKPT(sbi)->ckpt_flags &= (~CP_ORPHAN_PRESENT_FLAG); ++ sbi->por_doing = 0; ++ return 0; ++} ++ ++static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk) ++{ ++ struct list_head *head, *this, *next; ++ struct f2fs_orphan_block *orphan_blk = NULL; ++ struct page *page = NULL; ++ unsigned int nentries = 0; ++ unsigned short index = 1; ++ unsigned short orphan_blocks; ++ ++ orphan_blocks = (unsigned short)((sbi->n_orphans + ++ (F2FS_ORPHANS_PER_BLOCK - 1)) / F2FS_ORPHANS_PER_BLOCK); ++ ++ mutex_lock(&sbi->orphan_inode_mutex); ++ head = &sbi->orphan_inode_list; ++ ++ /* loop for each orphan inode entry and write them in Jornal block */ ++ list_for_each_safe(this, next, head) { ++ struct orphan_inode_entry *orphan; ++ ++ orphan = list_entry(this, struct orphan_inode_entry, list); ++ ++ if (nentries == F2FS_ORPHANS_PER_BLOCK) { ++ /* ++ * an orphan block is full of 1020 entries, ++ * then we need to flush current orphan blocks ++ * and bring another one in memory ++ */ ++ orphan_blk->blk_addr = cpu_to_le16(index); ++ orphan_blk->blk_count = cpu_to_le16(orphan_blocks); ++ orphan_blk->entry_count = cpu_to_le32(nentries); ++ set_page_dirty(page); ++ f2fs_put_page(page, 1); ++ index++; ++ start_blk++; ++ nentries = 0; ++ page = NULL; ++ } ++ if (page) ++ goto page_exist; ++ ++ page = grab_meta_page(sbi, start_blk); ++ orphan_blk = (struct f2fs_orphan_block *)page_address(page); ++ memset(orphan_blk, 0, sizeof(*orphan_blk)); ++page_exist: ++ orphan_blk->ino[nentries++] = cpu_to_le32(orphan->ino); ++ } ++ if (!page) ++ goto end; ++ ++ orphan_blk->blk_addr = cpu_to_le16(index); ++ orphan_blk->blk_count = cpu_to_le16(orphan_blocks); ++ orphan_blk->entry_count = cpu_to_le32(nentries); ++ set_page_dirty(page); ++ f2fs_put_page(page, 1); ++end: ++ mutex_unlock(&sbi->orphan_inode_mutex); ++} ++ ++static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, ++ block_t cp_addr, unsigned long long *version) ++{ ++ struct page *cp_page_1, *cp_page_2 = NULL; ++ unsigned long blk_size = sbi->blocksize; ++ struct f2fs_checkpoint *cp_block; ++ unsigned long long cur_version = 0, pre_version = 0; ++ unsigned int crc = 0; ++ size_t crc_offset; ++ ++ /* Read the 1st cp block in this CP pack */ ++ cp_page_1 = get_meta_page(sbi, cp_addr); ++ ++ /* get the version number */ ++ cp_block = (struct f2fs_checkpoint *)page_address(cp_page_1); ++ crc_offset = le32_to_cpu(cp_block->checksum_offset); ++ if (crc_offset >= blk_size) ++ goto invalid_cp1; ++ ++ crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset); ++ if (!f2fs_crc_valid(crc, cp_block, crc_offset)) ++ goto invalid_cp1; ++ ++ pre_version = le64_to_cpu(cp_block->checkpoint_ver); ++ ++ /* Read the 2nd cp block in this CP pack */ ++ cp_addr += le64_to_cpu(cp_block->cp_pack_total_block_count) - 1; ++ cp_page_2 = get_meta_page(sbi, cp_addr); ++ ++ cp_block = (struct f2fs_checkpoint *)page_address(cp_page_2); ++ crc_offset = le32_to_cpu(cp_block->checksum_offset); ++ if (crc_offset >= blk_size) ++ goto invalid_cp2; ++ ++ crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset); ++ if (!f2fs_crc_valid(crc, cp_block, crc_offset)) ++ goto invalid_cp2; ++ ++ cur_version = le64_to_cpu(cp_block->checkpoint_ver); ++ ++ if (cur_version == pre_version) { ++ *version = cur_version; ++ f2fs_put_page(cp_page_2, 1); ++ return cp_page_1; ++ } ++invalid_cp2: ++ f2fs_put_page(cp_page_2, 1); ++invalid_cp1: ++ f2fs_put_page(cp_page_1, 1); ++ return NULL; ++} ++ ++int get_valid_checkpoint(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_checkpoint *cp_block; ++ struct f2fs_super_block *fsb = sbi->raw_super; ++ struct page *cp1, *cp2, *cur_page; ++ unsigned long blk_size = sbi->blocksize; ++ unsigned long long cp1_version = 0, cp2_version = 0; ++ unsigned long long cp_start_blk_no; ++ ++ sbi->ckpt = kzalloc(blk_size, GFP_KERNEL); ++ if (!sbi->ckpt) ++ return -ENOMEM; ++ /* ++ * Finding out valid cp block involves read both ++ * sets( cp pack1 and cp pack 2) ++ */ ++ cp_start_blk_no = le32_to_cpu(fsb->start_segment_checkpoint); ++ cp1 = validate_checkpoint(sbi, cp_start_blk_no, &cp1_version); ++ ++ /* The second checkpoint pack should start at the next segment */ ++ cp_start_blk_no += 1 << le32_to_cpu(fsb->log_blocks_per_seg); ++ cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version); ++ ++ if (cp1 && cp2) { ++ if (ver_after(cp2_version, cp1_version)) ++ cur_page = cp2; ++ else ++ cur_page = cp1; ++ } else if (cp1) { ++ cur_page = cp1; ++ } else if (cp2) { ++ cur_page = cp2; ++ } else { ++ goto fail_no_cp; ++ } ++ ++ cp_block = (struct f2fs_checkpoint *)page_address(cur_page); ++ memcpy(sbi->ckpt, cp_block, blk_size); ++ ++ f2fs_put_page(cp1, 1); ++ f2fs_put_page(cp2, 1); ++ return 0; ++ ++fail_no_cp: ++ kfree(sbi->ckpt); ++ return -EINVAL; ++} ++ ++void set_dirty_dir_page(struct inode *inode, struct page *page) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct list_head *head = &sbi->dir_inode_list; ++ struct dir_inode_entry *new; ++ struct list_head *this; ++ ++ if (!S_ISDIR(inode->i_mode)) ++ return; ++retry: ++ new = kmem_cache_alloc(inode_entry_slab, GFP_NOFS); ++ if (!new) { ++ cond_resched(); ++ goto retry; ++ } ++ new->inode = inode; ++ INIT_LIST_HEAD(&new->list); ++ ++ spin_lock(&sbi->dir_inode_lock); ++ list_for_each(this, head) { ++ struct dir_inode_entry *entry; ++ entry = list_entry(this, struct dir_inode_entry, list); ++ if (entry->inode == inode) { ++ kmem_cache_free(inode_entry_slab, new); ++ goto out; ++ } ++ } ++ list_add_tail(&new->list, head); ++ sbi->n_dirty_dirs++; ++ ++ BUG_ON(!S_ISDIR(inode->i_mode)); ++out: ++ inc_page_count(sbi, F2FS_DIRTY_DENTS); ++ inode_inc_dirty_dents(inode); ++ SetPagePrivate(page); ++ ++ spin_unlock(&sbi->dir_inode_lock); ++} ++ ++void remove_dirty_dir_inode(struct inode *inode) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct list_head *head = &sbi->dir_inode_list; ++ struct list_head *this; ++ ++ if (!S_ISDIR(inode->i_mode)) ++ return; ++ ++ spin_lock(&sbi->dir_inode_lock); ++ if (atomic_read(&F2FS_I(inode)->dirty_dents)) ++ goto out; ++ ++ list_for_each(this, head) { ++ struct dir_inode_entry *entry; ++ entry = list_entry(this, struct dir_inode_entry, list); ++ if (entry->inode == inode) { ++ list_del(&entry->list); ++ kmem_cache_free(inode_entry_slab, entry); ++ sbi->n_dirty_dirs--; ++ break; ++ } ++ } ++out: ++ spin_unlock(&sbi->dir_inode_lock); ++} ++ ++void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) ++{ ++ struct list_head *head = &sbi->dir_inode_list; ++ struct dir_inode_entry *entry; ++ struct inode *inode; ++retry: ++ spin_lock(&sbi->dir_inode_lock); ++ if (list_empty(head)) { ++ spin_unlock(&sbi->dir_inode_lock); ++ return; ++ } ++ entry = list_entry(head->next, struct dir_inode_entry, list); ++ inode = igrab(entry->inode); ++ spin_unlock(&sbi->dir_inode_lock); ++ if (inode) { ++ filemap_flush(inode->i_mapping); ++ iput(inode); ++ } else { ++ /* ++ * We should submit bio, since it exists several ++ * wribacking dentry pages in the freeing inode. ++ */ ++ f2fs_submit_bio(sbi, DATA, true); ++ } ++ goto retry; ++} ++ ++/** ++ * Freeze all the FS-operations for checkpoint. ++ */ ++void block_operations(struct f2fs_sb_info *sbi) ++{ ++ int t; ++ struct writeback_control wbc = { ++ .sync_mode = WB_SYNC_ALL, ++ .nr_to_write = LONG_MAX, ++ .for_reclaim = 0, ++ }; ++ ++ /* Stop renaming operation */ ++ mutex_lock_op(sbi, RENAME); ++ mutex_lock_op(sbi, DENTRY_OPS); ++ ++retry_dents: ++ /* write all the dirty dentry pages */ ++ sync_dirty_dir_inodes(sbi); ++ ++ mutex_lock_op(sbi, DATA_WRITE); ++ if (get_pages(sbi, F2FS_DIRTY_DENTS)) { ++ mutex_unlock_op(sbi, DATA_WRITE); ++ goto retry_dents; ++ } ++ ++ /* block all the operations */ ++ for (t = DATA_NEW; t <= NODE_TRUNC; t++) ++ mutex_lock_op(sbi, t); ++ ++ mutex_lock(&sbi->write_inode); ++ ++ /* ++ * POR: we should ensure that there is no dirty node pages ++ * until finishing nat/sit flush. ++ */ ++retry: ++ sync_node_pages(sbi, 0, &wbc); ++ ++ mutex_lock_op(sbi, NODE_WRITE); ++ ++ if (get_pages(sbi, F2FS_DIRTY_NODES)) { ++ mutex_unlock_op(sbi, NODE_WRITE); ++ goto retry; ++ } ++ mutex_unlock(&sbi->write_inode); ++} ++ ++static void unblock_operations(struct f2fs_sb_info *sbi) ++{ ++ int t; ++ for (t = NODE_WRITE; t >= RENAME; t--) ++ mutex_unlock_op(sbi, t); ++} ++ ++static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) ++{ ++ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); ++ nid_t last_nid = 0; ++ int nat_upd_blkoff[3]; ++ block_t start_blk; ++ struct page *cp_page; ++ unsigned int data_sum_blocks, orphan_blocks; ++ void *kaddr; ++ __u32 crc32 = 0; ++ int i; ++ ++ /* Flush all the NAT/SIT pages */ ++ while (get_pages(sbi, F2FS_DIRTY_META)) ++ sync_meta_pages(sbi, META, LONG_MAX); ++ ++ next_free_nid(sbi, &last_nid); ++ ++ /* ++ * modify checkpoint ++ * version number is already updated ++ */ ++ ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi)); ++ ckpt->valid_block_count = cpu_to_le64(valid_user_blocks(sbi)); ++ ckpt->free_segment_count = cpu_to_le32(free_segments(sbi)); ++ for (i = 0; i < 3; i++) { ++ ckpt->cur_node_segno[i] = ++ cpu_to_le32(curseg_segno(sbi, i + CURSEG_HOT_NODE)); ++ ckpt->cur_node_blkoff[i] = ++ cpu_to_le16(curseg_blkoff(sbi, i + CURSEG_HOT_NODE)); ++ nat_upd_blkoff[i] = NM_I(sbi)->nat_upd_blkoff[i]; ++ ckpt->nat_upd_blkoff[i] = cpu_to_le16(nat_upd_blkoff[i]); ++ ckpt->alloc_type[i + CURSEG_HOT_NODE] = ++ curseg_alloc_type(sbi, i + CURSEG_HOT_NODE); ++ } ++ for (i = 0; i < 3; i++) { ++ ckpt->cur_data_segno[i] = ++ cpu_to_le32(curseg_segno(sbi, i + CURSEG_HOT_DATA)); ++ ckpt->cur_data_blkoff[i] = ++ cpu_to_le16(curseg_blkoff(sbi, i + CURSEG_HOT_DATA)); ++ ckpt->alloc_type[i + CURSEG_HOT_DATA] = ++ curseg_alloc_type(sbi, i + CURSEG_HOT_DATA); ++ } ++ ++ ckpt->valid_node_count = cpu_to_le32(valid_node_count(sbi)); ++ ckpt->valid_inode_count = cpu_to_le32(valid_inode_count(sbi)); ++ ckpt->next_free_nid = cpu_to_le32(last_nid); ++ ++ /* 2 cp + n data seg summary + orphan inode blocks */ ++ data_sum_blocks = npages_for_summary_flush(sbi); ++ if (data_sum_blocks < 3) ++ ckpt->ckpt_flags |= CP_COMPACT_SUM_FLAG; ++ else ++ ckpt->ckpt_flags &= (~CP_COMPACT_SUM_FLAG); ++ ++ orphan_blocks = (sbi->n_orphans + F2FS_ORPHANS_PER_BLOCK - 1) ++ / F2FS_ORPHANS_PER_BLOCK; ++ ckpt->cp_pack_start_sum = 1 + orphan_blocks; ++ ckpt->cp_pack_total_block_count = 2 + data_sum_blocks + orphan_blocks; ++ ++ if (is_umount) { ++ ckpt->ckpt_flags |= CP_UMOUNT_FLAG; ++ ckpt->cp_pack_total_block_count += NR_CURSEG_NODE_TYPE; ++ } else { ++ ckpt->ckpt_flags &= (~CP_UMOUNT_FLAG); ++ } ++ ++ if (sbi->n_orphans) ++ ckpt->ckpt_flags |= CP_ORPHAN_PRESENT_FLAG; ++ else ++ ckpt->ckpt_flags &= (~CP_ORPHAN_PRESENT_FLAG); ++ ++ /* update SIT/NAT bitmap */ ++ get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP)); ++ get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP)); ++ ++ crc32 = f2fs_crc32(ckpt, le32_to_cpu(ckpt->checksum_offset)); ++ *(__u32 *)((unsigned char *)ckpt + ++ le32_to_cpu(ckpt->checksum_offset)) ++ = cpu_to_le32(crc32); ++ ++ start_blk = __start_cp_addr(sbi); ++ ++ /* write out checkpoint buffer at block 0 */ ++ cp_page = grab_meta_page(sbi, start_blk++); ++ kaddr = page_address(cp_page); ++ memcpy(kaddr, ckpt, (1 << sbi->log_blocksize)); ++ set_page_dirty(cp_page); ++ f2fs_put_page(cp_page, 1); ++ ++ if (sbi->n_orphans) { ++ write_orphan_inodes(sbi, start_blk); ++ start_blk += orphan_blocks; ++ } ++ ++ write_data_summaries(sbi, start_blk); ++ start_blk += data_sum_blocks; ++ if (is_umount) { ++ write_node_summaries(sbi, start_blk); ++ start_blk += NR_CURSEG_NODE_TYPE; ++ } ++ ++ /* writeout checkpoint block */ ++ cp_page = grab_meta_page(sbi, start_blk); ++ kaddr = page_address(cp_page); ++ memcpy(kaddr, ckpt, (1 << sbi->log_blocksize)); ++ set_page_dirty(cp_page); ++ f2fs_put_page(cp_page, 1); ++ ++ /* wait for previous submitted node/meta pages writeback */ ++ while (get_pages(sbi, F2FS_WRITEBACK)) ++ congestion_wait(BLK_RW_ASYNC, HZ / 50); ++ ++ filemap_fdatawait_range(sbi->node_inode->i_mapping, 0, LONG_MAX); ++ filemap_fdatawait_range(sbi->meta_inode->i_mapping, 0, LONG_MAX); ++ ++ /* update user_block_counts */ ++ sbi->last_valid_block_count = sbi->total_valid_block_count; ++ sbi->alloc_valid_block_count = 0; ++ ++ /* Here, we only have one bio having CP pack */ ++ if (sbi->ckpt->ckpt_flags & CP_ERROR_FLAG) ++ sbi->sb->s_flags |= MS_RDONLY; ++ else ++ sync_meta_pages(sbi, META_FLUSH, LONG_MAX); ++ ++ clear_prefree_segments(sbi); ++ F2FS_RESET_SB_DIRT(sbi); ++} ++ ++/** ++ * We guarantee that this checkpoint procedure should not fail. ++ */ ++void write_checkpoint(struct f2fs_sb_info *sbi, bool blocked, bool is_umount) ++{ ++ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); ++ unsigned long long ckpt_ver; ++ ++ if (!blocked) { ++ mutex_lock(&sbi->cp_mutex); ++ block_operations(sbi); ++ } ++ ++ f2fs_submit_bio(sbi, DATA, true); ++ f2fs_submit_bio(sbi, NODE, true); ++ f2fs_submit_bio(sbi, META, true); ++ ++ /* ++ * update checkpoint pack index ++ * Increase the version number so that ++ * SIT entries and seg summaries are written at correct place ++ */ ++ ckpt_ver = le64_to_cpu(ckpt->checkpoint_ver); ++ ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver); ++ ++ /* write cached NAT/SIT entries to NAT/SIT area */ ++ flush_nat_entries(sbi); ++ flush_sit_entries(sbi); ++ ++ reset_victim_segmap(sbi); ++ ++ /* unlock all the fs_lock[] in do_checkpoint() */ ++ do_checkpoint(sbi, is_umount); ++ ++ unblock_operations(sbi); ++ mutex_unlock(&sbi->cp_mutex); ++} ++ ++void init_orphan_info(struct f2fs_sb_info *sbi) ++{ ++ mutex_init(&sbi->orphan_inode_mutex); ++ INIT_LIST_HEAD(&sbi->orphan_inode_list); ++ sbi->n_orphans = 0; ++} ++ ++int create_checkpoint_caches(void) ++{ ++ orphan_entry_slab = f2fs_kmem_cache_create("f2fs_orphan_entry", ++ sizeof(struct orphan_inode_entry), NULL); ++ if (unlikely(!orphan_entry_slab)) ++ return -ENOMEM; ++ inode_entry_slab = f2fs_kmem_cache_create("f2fs_dirty_dir_entry", ++ sizeof(struct dir_inode_entry), NULL); ++ if (unlikely(!inode_entry_slab)) { ++ kmem_cache_destroy(orphan_entry_slab); ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++void destroy_checkpoint_caches(void) ++{ ++ kmem_cache_destroy(orphan_entry_slab); ++ kmem_cache_destroy(inode_entry_slab); ++} diff --git a/patches/linux-3.7-rc6/0103-f2fs-add-node-operations.patch b/patches/linux-3.7-rc6/0103-f2fs-add-node-operations.patch new file mode 100644 index 0000000..0acac64 --- /dev/null +++ b/patches/linux-3.7-rc6/0103-f2fs-add-node-operations.patch @@ -0,0 +1,1824 @@ +From ccdfa2eae0b5f0324955f0f24f34e47dc926bad7 Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:28:19 +0000 +Subject: [PATCH] f2fs: add node operations + +This adds specific functions to manage NAT pages, a cache for NAT entries, free +nids, direct/indirect node blocks for indexing data, and address space for node +pages. + +- The key information of an NAT entry consists of a node id and a block address. + +- An NAT page is composed of block addresses covered by a certain range of NAT + entries, which is maintained by the address space of meta_inode. + +- A radix tree structure is used to cache NAT entries. The index for the tree + is a node id. + +- When there is no free nid, F2FS should scan NAT entries to find new one. In + order to avoid scanning frequently, F2FS manages a list containing a number of + free nids in memory. Only when free nids in the list are exhausted, scanning + process, build_free_nids(), is triggered. + +- F2FS has direct and indirect node blocks for indexing data. This patch adds + fuctions related to the node block management such as getting, allocating, and + truncating node blocks to index data. + +- In order to cache node blocks in memory, F2FS has a node_inode with an address + space for node pages. This patch also adds the address space operations for + node_inode. + +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/f2fs/node.c | 1782 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 1782 insertions(+) + create mode 100644 fs/f2fs/node.c + +diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c +new file mode 100644 +index 0000000..df69058 +--- /dev/null ++++ b/fs/f2fs/node.c +@@ -0,0 +1,1782 @@ ++/** ++ * fs/f2fs/node.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/fs.h> ++#include <linux/f2fs_fs.h> ++#include <linux/mpage.h> ++#include <linux/backing-dev.h> ++#include <linux/blkdev.h> ++#include <linux/pagevec.h> ++#include <linux/swap.h> ++ ++#include "f2fs.h" ++#include "node.h" ++#include "segment.h" ++ ++static struct kmem_cache *nat_entry_slab; ++static struct kmem_cache *free_nid_slab; ++ ++static void clear_node_page_dirty(struct page *page) ++{ ++ struct address_space *mapping = page->mapping; ++ struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); ++ unsigned int long flags; ++ ++ if (PageDirty(page)) { ++ spin_lock_irqsave(&mapping->tree_lock, flags); ++ radix_tree_tag_clear(&mapping->page_tree, ++ page_index(page), ++ PAGECACHE_TAG_DIRTY); ++ spin_unlock_irqrestore(&mapping->tree_lock, flags); ++ ++ clear_page_dirty_for_io(page); ++ dec_page_count(sbi, F2FS_DIRTY_NODES); ++ } ++ ClearPageUptodate(page); ++} ++ ++static struct page *get_current_nat_page(struct f2fs_sb_info *sbi, nid_t nid) ++{ ++ pgoff_t index = current_nat_addr(sbi, nid); ++ return get_meta_page(sbi, index); ++} ++ ++static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid) ++{ ++ struct page *src_page; ++ struct page *dst_page; ++ pgoff_t src_off; ++ pgoff_t dst_off; ++ void *src_addr; ++ void *dst_addr; ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ ++ src_off = current_nat_addr(sbi, nid); ++ dst_off = next_nat_addr(sbi, src_off); ++ ++ /* get current nat block page with lock */ ++ src_page = get_meta_page(sbi, src_off); ++ ++ /* Dirty src_page means that it is already the new target NAT page. */ ++ if (PageDirty(src_page)) ++ return src_page; ++ ++ dst_page = grab_meta_page(sbi, dst_off); ++ ++ src_addr = page_address(src_page); ++ dst_addr = page_address(dst_page); ++ memcpy(dst_addr, src_addr, PAGE_CACHE_SIZE); ++ set_page_dirty(dst_page); ++ f2fs_put_page(src_page, 1); ++ ++ set_to_next_nat(nm_i, nid); ++ ++ return dst_page; ++} ++ ++/** ++ * Readahead NAT pages ++ */ ++static void ra_nat_pages(struct f2fs_sb_info *sbi, int nid) ++{ ++ struct address_space *mapping = sbi->meta_inode->i_mapping; ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ struct page *page; ++ pgoff_t index; ++ int i; ++ ++ for (i = 0; i < FREE_NID_PAGES; i++, nid += NAT_ENTRY_PER_BLOCK) { ++ if (nid >= nm_i->max_nid) ++ nid = 0; ++ index = current_nat_addr(sbi, nid); ++ ++ page = grab_cache_page(mapping, index); ++ if (!page) ++ continue; ++ if (f2fs_readpage(sbi, page, index, READ)) { ++ f2fs_put_page(page, 1); ++ continue; ++ } ++ page_cache_release(page); ++ } ++} ++ ++static struct nat_entry *__lookup_nat_cache(struct f2fs_nm_info *nm_i, nid_t n) ++{ ++ return radix_tree_lookup(&nm_i->nat_root, n); ++} ++ ++static unsigned int __gang_lookup_nat_cache(struct f2fs_nm_info *nm_i, ++ nid_t start, unsigned int nr, struct nat_entry **ep) ++{ ++ return radix_tree_gang_lookup(&nm_i->nat_root, (void **)ep, start, nr); ++} ++ ++static void __del_from_nat_cache(struct f2fs_nm_info *nm_i, struct nat_entry *e) ++{ ++ list_del(&e->list); ++ radix_tree_delete(&nm_i->nat_root, nat_get_nid(e)); ++ nm_i->nat_cnt--; ++ kmem_cache_free(nat_entry_slab, e); ++} ++ ++int is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid) ++{ ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ struct nat_entry *e; ++ int is_cp = 1; ++ ++ read_lock(&nm_i->nat_tree_lock); ++ e = __lookup_nat_cache(nm_i, nid); ++ if (e && !e->checkpointed) ++ is_cp = 0; ++ read_unlock(&nm_i->nat_tree_lock); ++ return is_cp; ++} ++ ++static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid) ++{ ++ struct nat_entry *new; ++ ++ new = kmem_cache_alloc(nat_entry_slab, GFP_ATOMIC); ++ if (!new) ++ return NULL; ++ if (radix_tree_insert(&nm_i->nat_root, nid, new)) { ++ kmem_cache_free(nat_entry_slab, new); ++ return NULL; ++ } ++ memset(new, 0, sizeof(struct nat_entry)); ++ nat_set_nid(new, nid); ++ list_add_tail(&new->list, &nm_i->nat_entries); ++ nm_i->nat_cnt++; ++ return new; ++} ++ ++static void cache_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid, ++ struct f2fs_nat_entry *ne) ++{ ++ struct nat_entry *e; ++retry: ++ write_lock(&nm_i->nat_tree_lock); ++ e = __lookup_nat_cache(nm_i, nid); ++ if (!e) { ++ e = grab_nat_entry(nm_i, nid); ++ if (!e) { ++ write_unlock(&nm_i->nat_tree_lock); ++ goto retry; ++ } ++ nat_set_blkaddr(e, le32_to_cpu(ne->block_addr)); ++ nat_set_ino(e, le32_to_cpu(ne->ino)); ++ nat_set_version(e, ne->version); ++ e->checkpointed = true; ++ } ++ write_unlock(&nm_i->nat_tree_lock); ++} ++ ++static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni, ++ block_t new_blkaddr) ++{ ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ struct nat_entry *e; ++retry: ++ write_lock(&nm_i->nat_tree_lock); ++ e = __lookup_nat_cache(nm_i, ni->nid); ++ if (!e) { ++ e = grab_nat_entry(nm_i, ni->nid); ++ if (!e) { ++ write_unlock(&nm_i->nat_tree_lock); ++ goto retry; ++ } ++ e->ni = *ni; ++ e->checkpointed = true; ++ BUG_ON(ni->blk_addr == NEW_ADDR); ++ } else if (new_blkaddr == NEW_ADDR) { ++ /* ++ * when nid is reallocated, ++ * previous nat entry can be remained in nat cache. ++ * So, reinitialize it with new information. ++ */ ++ e->ni = *ni; ++ BUG_ON(ni->blk_addr != NULL_ADDR); ++ } ++ ++ if (new_blkaddr == NEW_ADDR) ++ e->checkpointed = false; ++ ++ /* sanity check */ ++ BUG_ON(nat_get_blkaddr(e) != ni->blk_addr); ++ BUG_ON(nat_get_blkaddr(e) == NULL_ADDR && ++ new_blkaddr == NULL_ADDR); ++ BUG_ON(nat_get_blkaddr(e) == NEW_ADDR && ++ new_blkaddr == NEW_ADDR); ++ BUG_ON(nat_get_blkaddr(e) != NEW_ADDR && ++ nat_get_blkaddr(e) != NULL_ADDR && ++ new_blkaddr == NEW_ADDR); ++ ++ /* increament version no as node is removed */ ++ if (nat_get_blkaddr(e) != NEW_ADDR && new_blkaddr == NULL_ADDR) { ++ unsigned char version = nat_get_version(e); ++ nat_set_version(e, inc_node_version(version)); ++ } ++ ++ /* change address */ ++ nat_set_blkaddr(e, new_blkaddr); ++ __set_nat_cache_dirty(nm_i, e); ++ write_unlock(&nm_i->nat_tree_lock); ++} ++ ++static int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink) ++{ ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ ++ if (nm_i->nat_cnt < 2 * NM_WOUT_THRESHOLD) ++ return 0; ++ ++ write_lock(&nm_i->nat_tree_lock); ++ while (nr_shrink && !list_empty(&nm_i->nat_entries)) { ++ struct nat_entry *ne; ++ ne = list_first_entry(&nm_i->nat_entries, ++ struct nat_entry, list); ++ __del_from_nat_cache(nm_i, ne); ++ nr_shrink--; ++ } ++ write_unlock(&nm_i->nat_tree_lock); ++ return nr_shrink; ++} ++ ++/** ++ * This function returns always success ++ */ ++void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) ++{ ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); ++ struct f2fs_summary_block *sum = curseg->sum_blk; ++ nid_t start_nid = START_NID(nid); ++ struct f2fs_nat_block *nat_blk; ++ struct page *page = NULL; ++ struct f2fs_nat_entry ne; ++ struct nat_entry *e; ++ int i; ++ ++ ni->nid = nid; ++ ++ /* Check nat cache */ ++ read_lock(&nm_i->nat_tree_lock); ++ e = __lookup_nat_cache(nm_i, nid); ++ if (e) { ++ ni->ino = nat_get_ino(e); ++ ni->blk_addr = nat_get_blkaddr(e); ++ ni->version = nat_get_version(e); ++ } ++ read_unlock(&nm_i->nat_tree_lock); ++ if (e) ++ return; ++ ++ /* Check current segment summary */ ++ mutex_lock(&curseg->curseg_mutex); ++ i = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 0); ++ if (i >= 0) { ++ ne = nat_in_journal(sum, i); ++ node_info_from_raw_nat(ni, &ne); ++ } ++ mutex_unlock(&curseg->curseg_mutex); ++ if (i >= 0) ++ goto cache; ++ ++ /* Fill node_info from nat page */ ++ page = get_current_nat_page(sbi, start_nid); ++ nat_blk = (struct f2fs_nat_block *)page_address(page); ++ ne = nat_blk->entries[nid - start_nid]; ++ node_info_from_raw_nat(ni, &ne); ++ f2fs_put_page(page, 1); ++cache: ++ /* cache nat entry */ ++ cache_nat_entry(NM_I(sbi), nid, &ne); ++} ++ ++/** ++ * The maximum depth is four. ++ * Offset[0] will have raw inode offset. ++ */ ++static int get_node_path(long block, int offset[4], unsigned int noffset[4]) ++{ ++ const long direct_index = ADDRS_PER_INODE; ++ const long direct_blks = ADDRS_PER_BLOCK; ++ const long dptrs_per_blk = NIDS_PER_BLOCK; ++ const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK; ++ const long dindirect_blks = indirect_blks * NIDS_PER_BLOCK; ++ int n = 0; ++ int level = 0; ++ ++ noffset[0] = 0; ++ ++ if (block < direct_index) { ++ offset[n++] = block; ++ level = 0; ++ goto got; ++ } ++ block -= direct_index; ++ if (block < direct_blks) { ++ offset[n++] = NODE_DIR1_BLOCK; ++ noffset[n] = 1; ++ offset[n++] = block; ++ level = 1; ++ goto got; ++ } ++ block -= direct_blks; ++ if (block < direct_blks) { ++ offset[n++] = NODE_DIR2_BLOCK; ++ noffset[n] = 2; ++ offset[n++] = block; ++ level = 1; ++ goto got; ++ } ++ block -= direct_blks; ++ if (block < indirect_blks) { ++ offset[n++] = NODE_IND1_BLOCK; ++ noffset[n] = 3; ++ offset[n++] = block / direct_blks; ++ noffset[n] = 4 + offset[n - 1]; ++ offset[n++] = block % direct_blks; ++ level = 2; ++ goto got; ++ } ++ block -= indirect_blks; ++ if (block < indirect_blks) { ++ offset[n++] = NODE_IND2_BLOCK; ++ noffset[n] = 4 + dptrs_per_blk; ++ offset[n++] = block / direct_blks; ++ noffset[n] = 5 + dptrs_per_blk + offset[n - 1]; ++ offset[n++] = block % direct_blks; ++ level = 2; ++ goto got; ++ } ++ block -= indirect_blks; ++ if (block < dindirect_blks) { ++ offset[n++] = NODE_DIND_BLOCK; ++ noffset[n] = 5 + (dptrs_per_blk * 2); ++ offset[n++] = block / indirect_blks; ++ noffset[n] = 6 + (dptrs_per_blk * 2) + ++ offset[n - 1] * (dptrs_per_blk + 1); ++ offset[n++] = (block / direct_blks) % dptrs_per_blk; ++ noffset[n] = 7 + (dptrs_per_blk * 2) + ++ offset[n - 2] * (dptrs_per_blk + 1) + ++ offset[n - 1]; ++ offset[n++] = block % direct_blks; ++ level = 3; ++ goto got; ++ } else { ++ BUG(); ++ } ++got: ++ return level; ++} ++ ++/* ++ * Caller should call f2fs_put_dnode(dn). ++ */ ++int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int ro) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); ++ struct page *npage[4]; ++ struct page *parent; ++ int offset[4]; ++ unsigned int noffset[4]; ++ nid_t nids[4]; ++ int level, i; ++ int err = 0; ++ ++ level = get_node_path(index, offset, noffset); ++ ++ nids[0] = dn->inode->i_ino; ++ npage[0] = get_node_page(sbi, nids[0]); ++ if (IS_ERR(npage[0])) ++ return PTR_ERR(npage[0]); ++ ++ parent = npage[0]; ++ nids[1] = get_nid(parent, offset[0], true); ++ dn->inode_page = npage[0]; ++ dn->inode_page_locked = true; ++ ++ /* get indirect or direct nodes */ ++ for (i = 1; i <= level; i++) { ++ bool done = false; ++ ++ if (!nids[i] && !ro) { ++ mutex_lock_op(sbi, NODE_NEW); ++ ++ /* alloc new node */ ++ if (!alloc_nid(sbi, &(nids[i]))) { ++ mutex_unlock_op(sbi, NODE_NEW); ++ err = -ENOSPC; ++ goto release_pages; ++ } ++ ++ dn->nid = nids[i]; ++ npage[i] = new_node_page(dn, noffset[i]); ++ if (IS_ERR(npage[i])) { ++ alloc_nid_failed(sbi, nids[i]); ++ mutex_unlock_op(sbi, NODE_NEW); ++ err = PTR_ERR(npage[i]); ++ goto release_pages; ++ } ++ ++ set_nid(parent, offset[i - 1], nids[i], i == 1); ++ alloc_nid_done(sbi, nids[i]); ++ mutex_unlock_op(sbi, NODE_NEW); ++ done = true; ++ } else if (ro && i == level && level > 1) { ++ npage[i] = get_node_page_ra(parent, offset[i - 1]); ++ if (IS_ERR(npage[i])) { ++ err = PTR_ERR(npage[i]); ++ goto release_pages; ++ } ++ done = true; ++ } ++ if (i == 1) { ++ dn->inode_page_locked = false; ++ unlock_page(parent); ++ } else { ++ f2fs_put_page(parent, 1); ++ } ++ ++ if (!done) { ++ npage[i] = get_node_page(sbi, nids[i]); ++ if (IS_ERR(npage[i])) { ++ err = PTR_ERR(npage[i]); ++ f2fs_put_page(npage[0], 0); ++ goto release_out; ++ } ++ } ++ if (i < level) { ++ parent = npage[i]; ++ nids[i + 1] = get_nid(parent, offset[i], false); ++ } ++ } ++ dn->nid = nids[level]; ++ dn->ofs_in_node = offset[level]; ++ dn->node_page = npage[level]; ++ dn->data_blkaddr = datablock_addr(dn->node_page, dn->ofs_in_node); ++ return 0; ++ ++release_pages: ++ f2fs_put_page(parent, 1); ++ if (i > 1) ++ f2fs_put_page(npage[0], 0); ++release_out: ++ dn->inode_page = NULL; ++ dn->node_page = NULL; ++ return err; ++} ++ ++static void truncate_node(struct dnode_of_data *dn) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); ++ struct node_info ni; ++ ++ get_node_info(sbi, dn->nid, &ni); ++ BUG_ON(ni.blk_addr == NULL_ADDR); ++ ++ if (ni.blk_addr != NULL_ADDR) ++ invalidate_blocks(sbi, ni.blk_addr); ++ ++ /* Deallocate node address */ ++ dec_valid_node_count(sbi, dn->inode, 1); ++ set_node_addr(sbi, &ni, NULL_ADDR); ++ ++ if (dn->nid == dn->inode->i_ino) { ++ remove_orphan_inode(sbi, dn->nid); ++ dec_valid_inode_count(sbi); ++ } else { ++ sync_inode_page(dn); ++ } ++ ++ clear_node_page_dirty(dn->node_page); ++ F2FS_SET_SB_DIRT(sbi); ++ ++ f2fs_put_page(dn->node_page, 1); ++ dn->node_page = NULL; ++} ++ ++static int truncate_dnode(struct dnode_of_data *dn) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); ++ struct page *page; ++ ++ if (dn->nid == 0) ++ return 1; ++ ++ /* get direct node */ ++ page = get_node_page(sbi, dn->nid); ++ if (IS_ERR(page) && PTR_ERR(page) == -ENOENT) ++ return 1; ++ else if (IS_ERR(page)) ++ return PTR_ERR(page); ++ ++ /* Make dnode_of_data for parameter */ ++ dn->node_page = page; ++ dn->ofs_in_node = 0; ++ truncate_data_blocks(dn); ++ truncate_node(dn); ++ return 1; ++} ++ ++static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs, ++ int ofs, int depth) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); ++ struct dnode_of_data rdn = *dn; ++ struct page *page; ++ struct f2fs_node *rn; ++ nid_t child_nid; ++ unsigned int child_nofs; ++ int freed = 0; ++ int i, ret; ++ ++ if (dn->nid == 0) ++ return NIDS_PER_BLOCK + 1; ++ ++ page = get_node_page(sbi, dn->nid); ++ if (IS_ERR(page)) ++ return PTR_ERR(page); ++ ++ rn = (struct f2fs_node *)page_address(page); ++ if (depth < 3) { ++ for (i = ofs; i < NIDS_PER_BLOCK; i++, freed++) { ++ child_nid = le32_to_cpu(rn->in.nid[i]); ++ if (child_nid == 0) ++ continue; ++ rdn.nid = child_nid; ++ ret = truncate_dnode(&rdn); ++ if (ret < 0) ++ goto out_err; ++ set_nid(page, i, 0, false); ++ } ++ } else { ++ child_nofs = nofs + ofs * (NIDS_PER_BLOCK + 1) + 1; ++ for (i = ofs; i < NIDS_PER_BLOCK; i++) { ++ child_nid = le32_to_cpu(rn->in.nid[i]); ++ if (child_nid == 0) { ++ child_nofs += NIDS_PER_BLOCK + 1; ++ continue; ++ } ++ rdn.nid = child_nid; ++ ret = truncate_nodes(&rdn, child_nofs, 0, depth - 1); ++ if (ret == (NIDS_PER_BLOCK + 1)) { ++ set_nid(page, i, 0, false); ++ child_nofs += ret; ++ } else if (ret < 0 && ret != -ENOENT) { ++ goto out_err; ++ } ++ } ++ freed = child_nofs; ++ } ++ ++ if (!ofs) { ++ /* remove current indirect node */ ++ dn->node_page = page; ++ truncate_node(dn); ++ freed++; ++ } else { ++ f2fs_put_page(page, 1); ++ } ++ return freed; ++ ++out_err: ++ f2fs_put_page(page, 1); ++ return ret; ++} ++ ++static int truncate_partial_nodes(struct dnode_of_data *dn, ++ struct f2fs_inode *ri, int *offset, int depth) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); ++ struct page *pages[2]; ++ nid_t nid[3]; ++ nid_t child_nid; ++ int err = 0; ++ int i; ++ int idx = depth - 2; ++ ++ nid[0] = le32_to_cpu(ri->i_nid[offset[0] - NODE_DIR1_BLOCK]); ++ if (!nid[0]) ++ return 0; ++ ++ /* get indirect nodes in the path */ ++ for (i = 0; i < depth - 1; i++) { ++ /* refernece count'll be increased */ ++ pages[i] = get_node_page(sbi, nid[i]); ++ if (IS_ERR(pages[i])) { ++ depth = i + 1; ++ err = PTR_ERR(pages[i]); ++ goto fail; ++ } ++ nid[i + 1] = get_nid(pages[i], offset[i + 1], false); ++ } ++ ++ /* free direct nodes linked to a partial indirect node */ ++ for (i = offset[depth - 1]; i < NIDS_PER_BLOCK; i++) { ++ child_nid = get_nid(pages[idx], i, false); ++ if (!child_nid) ++ continue; ++ dn->nid = child_nid; ++ err = truncate_dnode(dn); ++ if (err < 0) ++ goto fail; ++ set_nid(pages[idx], i, 0, false); ++ } ++ ++ if (offset[depth - 1] == 0) { ++ dn->node_page = pages[idx]; ++ dn->nid = nid[idx]; ++ truncate_node(dn); ++ } else { ++ f2fs_put_page(pages[idx], 1); ++ } ++ offset[idx]++; ++ offset[depth - 1] = 0; ++fail: ++ for (i = depth - 3; i >= 0; i--) ++ f2fs_put_page(pages[i], 1); ++ return err; ++} ++ ++/** ++ * All the block addresses of data and nodes should be nullified. ++ */ ++int truncate_inode_blocks(struct inode *inode, pgoff_t from) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ int err = 0, cont = 1; ++ int level, offset[4], noffset[4]; ++ unsigned int nofs; ++ struct f2fs_node *rn; ++ struct dnode_of_data dn; ++ struct page *page; ++ ++ level = get_node_path(from, offset, noffset); ++ ++ page = get_node_page(sbi, inode->i_ino); ++ if (IS_ERR(page)) ++ return PTR_ERR(page); ++ ++ set_new_dnode(&dn, inode, page, NULL, 0); ++ unlock_page(page); ++ ++ rn = page_address(page); ++ switch (level) { ++ case 0: ++ case 1: ++ nofs = noffset[1]; ++ break; ++ case 2: ++ nofs = noffset[1]; ++ if (!offset[level - 1]) ++ goto skip_partial; ++ err = truncate_partial_nodes(&dn, &rn->i, offset, level); ++ if (err < 0 && err != -ENOENT) ++ goto fail; ++ nofs += 1 + NIDS_PER_BLOCK; ++ break; ++ case 3: ++ nofs = 5 + 2 * NIDS_PER_BLOCK; ++ if (!offset[level - 1]) ++ goto skip_partial; ++ err = truncate_partial_nodes(&dn, &rn->i, offset, level); ++ if (err < 0 && err != -ENOENT) ++ goto fail; ++ break; ++ default: ++ BUG(); ++ } ++ ++skip_partial: ++ while (cont) { ++ dn.nid = le32_to_cpu(rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK]); ++ switch (offset[0]) { ++ case NODE_DIR1_BLOCK: ++ case NODE_DIR2_BLOCK: ++ err = truncate_dnode(&dn); ++ break; ++ ++ case NODE_IND1_BLOCK: ++ case NODE_IND2_BLOCK: ++ err = truncate_nodes(&dn, nofs, offset[1], 2); ++ break; ++ ++ case NODE_DIND_BLOCK: ++ err = truncate_nodes(&dn, nofs, offset[1], 3); ++ cont = 0; ++ break; ++ ++ default: ++ BUG(); ++ } ++ if (err < 0 && err != -ENOENT) ++ goto fail; ++ if (offset[1] == 0 && ++ rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK]) { ++ lock_page(page); ++ wait_on_page_writeback(page); ++ rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK] = 0; ++ set_page_dirty(page); ++ unlock_page(page); ++ } ++ offset[1] = 0; ++ offset[0]++; ++ nofs += err; ++ } ++fail: ++ f2fs_put_page(page, 0); ++ return err > 0 ? 0 : err; ++} ++ ++int remove_inode_page(struct inode *inode) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct page *page; ++ nid_t ino = inode->i_ino; ++ struct dnode_of_data dn; ++ ++ mutex_lock_op(sbi, NODE_TRUNC); ++ page = get_node_page(sbi, ino); ++ if (IS_ERR(page)) { ++ mutex_unlock_op(sbi, NODE_TRUNC); ++ return PTR_ERR(page); ++ } ++ ++ if (F2FS_I(inode)->i_xattr_nid) { ++ nid_t nid = F2FS_I(inode)->i_xattr_nid; ++ struct page *npage = get_node_page(sbi, nid); ++ ++ if (IS_ERR(npage)) { ++ mutex_unlock_op(sbi, NODE_TRUNC); ++ return PTR_ERR(npage); ++ } ++ ++ F2FS_I(inode)->i_xattr_nid = 0; ++ set_new_dnode(&dn, inode, page, npage, nid); ++ dn.inode_page_locked = 1; ++ truncate_node(&dn); ++ } ++ if (inode->i_blocks == 1) { ++ /* inernally call f2fs_put_page() */ ++ set_new_dnode(&dn, inode, page, page, ino); ++ truncate_node(&dn); ++ } else if (inode->i_blocks == 0) { ++ struct node_info ni; ++ get_node_info(sbi, inode->i_ino, &ni); ++ ++ /* called after f2fs_new_inode() is failed */ ++ BUG_ON(ni.blk_addr != NULL_ADDR); ++ f2fs_put_page(page, 1); ++ } else { ++ BUG(); ++ } ++ mutex_unlock_op(sbi, NODE_TRUNC); ++ return 0; ++} ++ ++int new_inode_page(struct inode *inode, struct dentry *dentry) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct page *page; ++ struct dnode_of_data dn; ++ ++ /* allocate inode page for new inode */ ++ set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino); ++ mutex_lock_op(sbi, NODE_NEW); ++ page = new_node_page(&dn, 0); ++ init_dent_inode(dentry, page); ++ mutex_unlock_op(sbi, NODE_NEW); ++ if (IS_ERR(page)) ++ return PTR_ERR(page); ++ f2fs_put_page(page, 1); ++ return 0; ++} ++ ++struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); ++ struct address_space *mapping = sbi->node_inode->i_mapping; ++ struct node_info old_ni, new_ni; ++ struct page *page; ++ int err; ++ ++ if (is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC)) ++ return ERR_PTR(-EPERM); ++ ++ page = grab_cache_page(mapping, dn->nid); ++ if (!page) ++ return ERR_PTR(-ENOMEM); ++ ++ get_node_info(sbi, dn->nid, &old_ni); ++ ++ SetPageUptodate(page); ++ fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true); ++ ++ /* Reinitialize old_ni with new node page */ ++ BUG_ON(old_ni.blk_addr != NULL_ADDR); ++ new_ni = old_ni; ++ new_ni.ino = dn->inode->i_ino; ++ ++ if (!inc_valid_node_count(sbi, dn->inode, 1)) { ++ err = -ENOSPC; ++ goto fail; ++ } ++ set_node_addr(sbi, &new_ni, NEW_ADDR); ++ ++ dn->node_page = page; ++ sync_inode_page(dn); ++ set_page_dirty(page); ++ set_cold_node(dn->inode, page); ++ if (ofs == 0) ++ inc_valid_inode_count(sbi); ++ ++ return page; ++ ++fail: ++ f2fs_put_page(page, 1); ++ return ERR_PTR(err); ++} ++ ++static int read_node_page(struct page *page, int type) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); ++ struct node_info ni; ++ ++ get_node_info(sbi, page->index, &ni); ++ ++ if (ni.blk_addr == NULL_ADDR) ++ return -ENOENT; ++ return f2fs_readpage(sbi, page, ni.blk_addr, type); ++} ++ ++/** ++ * Readahead a node page ++ */ ++void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid) ++{ ++ struct address_space *mapping = sbi->node_inode->i_mapping; ++ struct page *apage; ++ ++ apage = find_get_page(mapping, nid); ++ if (apage && PageUptodate(apage)) ++ goto release_out; ++ f2fs_put_page(apage, 0); ++ ++ apage = grab_cache_page(mapping, nid); ++ if (!apage) ++ return; ++ ++ if (read_node_page(apage, READA)) ++ goto unlock_out; ++ ++ page_cache_release(apage); ++ return; ++ ++unlock_out: ++ unlock_page(apage); ++release_out: ++ page_cache_release(apage); ++} ++ ++struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) ++{ ++ int err; ++ struct page *page; ++ struct address_space *mapping = sbi->node_inode->i_mapping; ++ ++ page = grab_cache_page(mapping, nid); ++ if (!page) ++ return ERR_PTR(-ENOMEM); ++ ++ err = read_node_page(page, READ_SYNC); ++ if (err) { ++ f2fs_put_page(page, 1); ++ return ERR_PTR(err); ++ } ++ ++ BUG_ON(nid != nid_of_node(page)); ++ mark_page_accessed(page); ++ return page; ++} ++ ++/** ++ * Return a locked page for the desired node page. ++ * And, readahead MAX_RA_NODE number of node pages. ++ */ ++struct page *get_node_page_ra(struct page *parent, int start) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(parent->mapping->host->i_sb); ++ struct address_space *mapping = sbi->node_inode->i_mapping; ++ int i, end; ++ int err = 0; ++ nid_t nid; ++ struct page *page; ++ ++ /* First, try getting the desired direct node. */ ++ nid = get_nid(parent, start, false); ++ if (!nid) ++ return ERR_PTR(-ENOENT); ++ ++ page = find_get_page(mapping, nid); ++ if (page && PageUptodate(page)) ++ goto page_hit; ++ f2fs_put_page(page, 0); ++ ++repeat: ++ page = grab_cache_page(mapping, nid); ++ if (!page) ++ return ERR_PTR(-ENOMEM); ++ ++ err = read_node_page(page, READA); ++ if (err) { ++ f2fs_put_page(page, 1); ++ return ERR_PTR(err); ++ } ++ ++ /* Then, try readahead for siblings of the desired node */ ++ end = start + MAX_RA_NODE; ++ end = min(end, NIDS_PER_BLOCK); ++ for (i = start + 1; i < end; i++) { ++ nid = get_nid(parent, i, false); ++ if (!nid) ++ continue; ++ ra_node_page(sbi, nid); ++ } ++ ++page_hit: ++ lock_page(page); ++ if (PageError(page)) { ++ f2fs_put_page(page, 1); ++ return ERR_PTR(-EIO); ++ } ++ ++ /* Has the page been truncated? */ ++ if (page->mapping != mapping) { ++ f2fs_put_page(page, 1); ++ goto repeat; ++ } ++ return page; ++} ++ ++void sync_inode_page(struct dnode_of_data *dn) ++{ ++ if (IS_INODE(dn->node_page) || dn->inode_page == dn->node_page) { ++ update_inode(dn->inode, dn->node_page); ++ } else if (dn->inode_page) { ++ if (!dn->inode_page_locked) ++ lock_page(dn->inode_page); ++ update_inode(dn->inode, dn->inode_page); ++ if (!dn->inode_page_locked) ++ unlock_page(dn->inode_page); ++ } else { ++ f2fs_write_inode(dn->inode, NULL); ++ } ++} ++ ++int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino, ++ struct writeback_control *wbc) ++{ ++ struct address_space *mapping = sbi->node_inode->i_mapping; ++ pgoff_t index, end; ++ struct pagevec pvec; ++ int step = ino ? 2 : 0; ++ int nwritten = 0, wrote = 0; ++ ++ pagevec_init(&pvec, 0); ++ ++next_step: ++ index = 0; ++ end = LONG_MAX; ++ ++ while (index <= end) { ++ int i, nr_pages; ++ nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, ++ PAGECACHE_TAG_DIRTY, ++ min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); ++ if (nr_pages == 0) ++ break; ++ ++ for (i = 0; i < nr_pages; i++) { ++ struct page *page = pvec.pages[i]; ++ ++ /* ++ * flushing sequence with step: ++ * 0. indirect nodes ++ * 1. dentry dnodes ++ * 2. file dnodes ++ */ ++ if (step == 0 && IS_DNODE(page)) ++ continue; ++ if (step == 1 && (!IS_DNODE(page) || ++ is_cold_node(page))) ++ continue; ++ if (step == 2 && (!IS_DNODE(page) || ++ !is_cold_node(page))) ++ continue; ++ ++ /* ++ * If an fsync mode, ++ * we should not skip writing node pages. ++ */ ++ if (ino && ino_of_node(page) == ino) ++ lock_page(page); ++ else if (!trylock_page(page)) ++ continue; ++ ++ if (unlikely(page->mapping != mapping)) { ++continue_unlock: ++ unlock_page(page); ++ continue; ++ } ++ if (ino && ino_of_node(page) != ino) ++ goto continue_unlock; ++ ++ if (!PageDirty(page)) { ++ /* someone wrote it for us */ ++ goto continue_unlock; ++ } ++ ++ if (!clear_page_dirty_for_io(page)) ++ goto continue_unlock; ++ ++ /* called by fsync() */ ++ if (ino && IS_DNODE(page)) { ++ int mark = !is_checkpointed_node(sbi, ino); ++ set_fsync_mark(page, 1); ++ if (IS_INODE(page)) ++ set_dentry_mark(page, mark); ++ nwritten++; ++ } else { ++ set_fsync_mark(page, 0); ++ set_dentry_mark(page, 0); ++ } ++ mapping->a_ops->writepage(page, wbc); ++ wrote++; ++ ++ if (--wbc->nr_to_write == 0) ++ break; ++ } ++ pagevec_release(&pvec); ++ cond_resched(); ++ ++ if (wbc->nr_to_write == 0) { ++ step = 2; ++ break; ++ } ++ } ++ ++ if (step < 2) { ++ step++; ++ goto next_step; ++ } ++ ++ if (wrote) ++ f2fs_submit_bio(sbi, NODE, wbc->sync_mode == WB_SYNC_ALL); ++ ++ return nwritten; ++} ++ ++static int f2fs_write_node_page(struct page *page, ++ struct writeback_control *wbc) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); ++ nid_t nid; ++ unsigned int nofs; ++ block_t new_addr; ++ struct node_info ni; ++ ++ if (wbc->for_reclaim) { ++ dec_page_count(sbi, F2FS_DIRTY_NODES); ++ wbc->pages_skipped++; ++ set_page_dirty(page); ++ return AOP_WRITEPAGE_ACTIVATE; ++ } ++ ++ wait_on_page_writeback(page); ++ ++ mutex_lock_op(sbi, NODE_WRITE); ++ ++ /* get old block addr of this node page */ ++ nid = nid_of_node(page); ++ nofs = ofs_of_node(page); ++ BUG_ON(page->index != nid); ++ ++ get_node_info(sbi, nid, &ni); ++ ++ /* This page is already truncated */ ++ if (ni.blk_addr == NULL_ADDR) ++ return 0; ++ ++ set_page_writeback(page); ++ ++ /* insert node offset */ ++ write_node_page(sbi, page, nid, ni.blk_addr, &new_addr); ++ set_node_addr(sbi, &ni, new_addr); ++ dec_page_count(sbi, F2FS_DIRTY_NODES); ++ ++ mutex_unlock_op(sbi, NODE_WRITE); ++ unlock_page(page); ++ return 0; ++} ++ ++static int f2fs_write_node_pages(struct address_space *mapping, ++ struct writeback_control *wbc) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); ++ struct block_device *bdev = sbi->sb->s_bdev; ++ long nr_to_write = wbc->nr_to_write; ++ ++ if (wbc->for_kupdate) ++ return 0; ++ ++ if (get_pages(sbi, F2FS_DIRTY_NODES) == 0) ++ return 0; ++ ++ if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK)) { ++ write_checkpoint(sbi, false, false); ++ return 0; ++ } ++ ++ /* if mounting is failed, skip writing node pages */ ++ wbc->nr_to_write = bio_get_nr_vecs(bdev); ++ sync_node_pages(sbi, 0, wbc); ++ wbc->nr_to_write = nr_to_write - ++ (bio_get_nr_vecs(bdev) - wbc->nr_to_write); ++ return 0; ++} ++ ++static int f2fs_set_node_page_dirty(struct page *page) ++{ ++ struct address_space *mapping = page->mapping; ++ struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); ++ ++ SetPageUptodate(page); ++ if (!PageDirty(page)) { ++ __set_page_dirty_nobuffers(page); ++ inc_page_count(sbi, F2FS_DIRTY_NODES); ++ SetPagePrivate(page); ++ return 1; ++ } ++ return 0; ++} ++ ++static void f2fs_invalidate_node_page(struct page *page, unsigned long offset) ++{ ++ struct inode *inode = page->mapping->host; ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ if (PageDirty(page)) ++ dec_page_count(sbi, F2FS_DIRTY_NODES); ++ ClearPagePrivate(page); ++} ++ ++static int f2fs_release_node_page(struct page *page, gfp_t wait) ++{ ++ ClearPagePrivate(page); ++ return 0; ++} ++ ++/** ++ * Structure of the f2fs node operations ++ */ ++const struct address_space_operations f2fs_node_aops = { ++ .writepage = f2fs_write_node_page, ++ .writepages = f2fs_write_node_pages, ++ .set_page_dirty = f2fs_set_node_page_dirty, ++ .invalidatepage = f2fs_invalidate_node_page, ++ .releasepage = f2fs_release_node_page, ++}; ++ ++static struct free_nid *__lookup_free_nid_list(nid_t n, struct list_head *head) ++{ ++ struct list_head *this; ++ struct free_nid *i = NULL; ++ list_for_each(this, head) { ++ i = list_entry(this, struct free_nid, list); ++ if (i->nid == n) ++ break; ++ i = NULL; ++ } ++ return i; ++} ++ ++static void __del_from_free_nid_list(struct free_nid *i) ++{ ++ list_del(&i->list); ++ kmem_cache_free(free_nid_slab, i); ++} ++ ++static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid) ++{ ++ struct free_nid *i; ++ ++ if (nm_i->fcnt > 2 * MAX_FREE_NIDS) ++ return 0; ++retry: ++ i = kmem_cache_alloc(free_nid_slab, GFP_NOFS); ++ if (!i) { ++ cond_resched(); ++ goto retry; ++ } ++ i->nid = nid; ++ i->state = NID_NEW; ++ ++ spin_lock(&nm_i->free_nid_list_lock); ++ if (__lookup_free_nid_list(nid, &nm_i->free_nid_list)) { ++ spin_unlock(&nm_i->free_nid_list_lock); ++ kmem_cache_free(free_nid_slab, i); ++ return 0; ++ } ++ list_add_tail(&i->list, &nm_i->free_nid_list); ++ nm_i->fcnt++; ++ spin_unlock(&nm_i->free_nid_list_lock); ++ return 1; ++} ++ ++static void remove_free_nid(struct f2fs_nm_info *nm_i, nid_t nid) ++{ ++ struct free_nid *i; ++ spin_lock(&nm_i->free_nid_list_lock); ++ i = __lookup_free_nid_list(nid, &nm_i->free_nid_list); ++ if (i && i->state == NID_NEW) { ++ __del_from_free_nid_list(i); ++ nm_i->fcnt--; ++ } ++ spin_unlock(&nm_i->free_nid_list_lock); ++} ++ ++static int scan_nat_page(struct f2fs_nm_info *nm_i, ++ struct page *nat_page, nid_t start_nid) ++{ ++ struct f2fs_nat_block *nat_blk = page_address(nat_page); ++ block_t blk_addr; ++ int fcnt = 0; ++ int i; ++ ++ /* 0 nid should not be used */ ++ if (start_nid == 0) ++ ++start_nid; ++ ++ i = start_nid % NAT_ENTRY_PER_BLOCK; ++ ++ for (; i < NAT_ENTRY_PER_BLOCK; i++, start_nid++) { ++ blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr); ++ BUG_ON(blk_addr == NEW_ADDR); ++ if (blk_addr == NULL_ADDR) ++ fcnt += add_free_nid(nm_i, start_nid); ++ } ++ return fcnt; ++} ++ ++static void build_free_nids(struct f2fs_sb_info *sbi) ++{ ++ struct free_nid *fnid, *next_fnid; ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); ++ struct f2fs_summary_block *sum = curseg->sum_blk; ++ nid_t nid = 0; ++ bool is_cycled = false; ++ int fcnt = 0; ++ int i; ++ ++ nid = nm_i->next_scan_nid; ++ nm_i->init_scan_nid = nid; ++ ++ ra_nat_pages(sbi, nid); ++ ++ while (1) { ++ struct page *page = get_current_nat_page(sbi, nid); ++ ++ fcnt += scan_nat_page(nm_i, page, nid); ++ f2fs_put_page(page, 1); ++ ++ nid += (NAT_ENTRY_PER_BLOCK - (nid % NAT_ENTRY_PER_BLOCK)); ++ ++ if (nid >= nm_i->max_nid) { ++ nid = 0; ++ is_cycled = true; ++ } ++ if (fcnt > MAX_FREE_NIDS) ++ break; ++ if (is_cycled && nm_i->init_scan_nid <= nid) ++ break; ++ } ++ ++ nm_i->next_scan_nid = nid; ++ ++ /* find free nids from current sum_pages */ ++ mutex_lock(&curseg->curseg_mutex); ++ for (i = 0; i < nats_in_cursum(sum); i++) { ++ block_t addr = le32_to_cpu(nat_in_journal(sum, i).block_addr); ++ nid = le32_to_cpu(nid_in_journal(sum, i)); ++ if (addr == NULL_ADDR) ++ add_free_nid(nm_i, nid); ++ else ++ remove_free_nid(nm_i, nid); ++ } ++ mutex_unlock(&curseg->curseg_mutex); ++ ++ /* remove the free nids from current allocated nids */ ++ list_for_each_entry_safe(fnid, next_fnid, &nm_i->free_nid_list, list) { ++ struct nat_entry *ne; ++ ++ read_lock(&nm_i->nat_tree_lock); ++ ne = __lookup_nat_cache(nm_i, fnid->nid); ++ if (ne && nat_get_blkaddr(ne) != NULL_ADDR) ++ remove_free_nid(nm_i, fnid->nid); ++ read_unlock(&nm_i->nat_tree_lock); ++ } ++} ++ ++/* ++ * If this function returns success, caller can obtain a new nid ++ * from second parameter of this function. ++ * The returned nid could be used ino as well as nid when inode is created. ++ */ ++bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid) ++{ ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ struct free_nid *i = NULL; ++ struct list_head *this; ++retry: ++ mutex_lock(&nm_i->build_lock); ++ if (!nm_i->fcnt) { ++ /* scan NAT in order to build free nid list */ ++ build_free_nids(sbi); ++ if (!nm_i->fcnt) { ++ mutex_unlock(&nm_i->build_lock); ++ return false; ++ } ++ } ++ mutex_unlock(&nm_i->build_lock); ++ ++ /* ++ * We check fcnt again since previous check is racy as ++ * we didn't hold free_nid_list_lock. So other thread ++ * could consume all of free nids. ++ */ ++ spin_lock(&nm_i->free_nid_list_lock); ++ if (!nm_i->fcnt) { ++ spin_unlock(&nm_i->free_nid_list_lock); ++ goto retry; ++ } ++ ++ BUG_ON(list_empty(&nm_i->free_nid_list)); ++ list_for_each(this, &nm_i->free_nid_list) { ++ i = list_entry(this, struct free_nid, list); ++ if (i->state == NID_NEW) ++ break; ++ } ++ ++ BUG_ON(i->state != NID_NEW); ++ *nid = i->nid; ++ i->state = NID_ALLOC; ++ nm_i->fcnt--; ++ spin_unlock(&nm_i->free_nid_list_lock); ++ return true; ++} ++ ++/** ++ * alloc_nid() should be called prior to this function. ++ */ ++void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid) ++{ ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ struct free_nid *i; ++ ++ spin_lock(&nm_i->free_nid_list_lock); ++ i = __lookup_free_nid_list(nid, &nm_i->free_nid_list); ++ if (i) { ++ BUG_ON(i->state != NID_ALLOC); ++ __del_from_free_nid_list(i); ++ } ++ spin_unlock(&nm_i->free_nid_list_lock); ++} ++ ++/** ++ * alloc_nid() should be called prior to this function. ++ */ ++void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid) ++{ ++ alloc_nid_done(sbi, nid); ++ add_free_nid(NM_I(sbi), nid); ++} ++ ++void recover_node_page(struct f2fs_sb_info *sbi, struct page *page, ++ struct f2fs_summary *sum, struct node_info *ni, ++ block_t new_blkaddr) ++{ ++ rewrite_node_page(sbi, page, sum, ni->blk_addr, new_blkaddr); ++ set_node_addr(sbi, ni, new_blkaddr); ++ clear_node_page_dirty(page); ++} ++ ++int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) ++{ ++ struct address_space *mapping = sbi->node_inode->i_mapping; ++ struct f2fs_node *rn; ++ void *src, *dst; ++ nid_t ino = ino_of_node(page); ++ struct node_info old_ni, new_ni; ++ struct page *ipage; ++ ++ ipage = grab_cache_page(mapping, ino); ++ if (!ipage) ++ return -ENOMEM; ++ ++ /* Should not use this inode from free nid list */ ++ remove_free_nid(NM_I(sbi), ino); ++ ++ get_node_info(sbi, ino, &old_ni); ++ SetPageUptodate(ipage); ++ fill_node_footer(ipage, ino, ino, 0, true); ++ ++ src = kmap_atomic(page); ++ dst = kmap_atomic(ipage); ++ ++ memcpy(dst, src, F2FS_INODE_SIZE); ++ rn = (struct f2fs_node *)dst; ++ rn->i.i_size = 0; ++ rn->i.i_blocks = 1; ++ rn->i.i_links = 1; ++ rn->i.i_xattr_nid = 0; ++ kunmap_atomic(dst); ++ kunmap_atomic(src); ++ ++ new_ni = old_ni; ++ new_ni.ino = ino; ++ ++ set_node_addr(sbi, &new_ni, NEW_ADDR); ++ inc_valid_inode_count(sbi); ++ ++ f2fs_put_page(ipage, 1); ++ return 0; ++} ++ ++int restore_node_summary(struct f2fs_sb_info *sbi, ++ unsigned int segno, struct f2fs_summary_block *sum) ++{ ++ struct f2fs_node *rn; ++ struct f2fs_summary *sum_entry; ++ struct page *page; ++ block_t addr; ++ int i, last_offset; ++ ++ /* alloc temporal page for read node */ ++ page = alloc_page(GFP_NOFS | __GFP_ZERO); ++ if (IS_ERR(page)) ++ return PTR_ERR(page); ++ lock_page(page); ++ ++ /* scan the node segment */ ++ last_offset = sbi->blocks_per_seg; ++ addr = START_BLOCK(sbi, segno); ++ sum_entry = &sum->entries[0]; ++ ++ for (i = 0; i < last_offset; i++, sum_entry++) { ++ if (f2fs_readpage(sbi, page, addr, READ_SYNC)) ++ goto out; ++ ++ rn = (struct f2fs_node *)page_address(page); ++ sum_entry->nid = rn->footer.nid; ++ sum_entry->version = 0; ++ sum_entry->ofs_in_node = 0; ++ addr++; ++ ++ /* ++ * In order to read next node page, ++ * we must clear PageUptodate flag. ++ */ ++ ClearPageUptodate(page); ++ } ++out: ++ unlock_page(page); ++ __free_pages(page, 0); ++ return 0; ++} ++ ++static bool flush_nats_in_journal(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); ++ struct f2fs_summary_block *sum = curseg->sum_blk; ++ int i; ++ ++ mutex_lock(&curseg->curseg_mutex); ++ ++ if (nats_in_cursum(sum) < NAT_JOURNAL_ENTRIES) { ++ mutex_unlock(&curseg->curseg_mutex); ++ return false; ++ } ++ ++ for (i = 0; i < nats_in_cursum(sum); i++) { ++ struct nat_entry *ne; ++ struct f2fs_nat_entry raw_ne; ++ nid_t nid = le32_to_cpu(nid_in_journal(sum, i)); ++ ++ raw_ne = nat_in_journal(sum, i); ++retry: ++ write_lock(&nm_i->nat_tree_lock); ++ ne = __lookup_nat_cache(nm_i, nid); ++ if (ne) { ++ __set_nat_cache_dirty(nm_i, ne); ++ write_unlock(&nm_i->nat_tree_lock); ++ continue; ++ } ++ ne = grab_nat_entry(nm_i, nid); ++ if (!ne) { ++ write_unlock(&nm_i->nat_tree_lock); ++ goto retry; ++ } ++ nat_set_blkaddr(ne, le32_to_cpu(raw_ne.block_addr)); ++ nat_set_ino(ne, le32_to_cpu(raw_ne.ino)); ++ nat_set_version(ne, raw_ne.version); ++ __set_nat_cache_dirty(nm_i, ne); ++ write_unlock(&nm_i->nat_tree_lock); ++ } ++ update_nats_in_cursum(sum, -i); ++ mutex_unlock(&curseg->curseg_mutex); ++ return true; ++} ++ ++/** ++ * This function is called during the checkpointing process. ++ */ ++void flush_nat_entries(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); ++ struct f2fs_summary_block *sum = curseg->sum_blk; ++ struct list_head *cur, *n; ++ struct page *page = NULL; ++ struct f2fs_nat_block *nat_blk = NULL; ++ nid_t start_nid = 0, end_nid = 0; ++ bool flushed; ++ ++ flushed = flush_nats_in_journal(sbi); ++ ++ if (!flushed) ++ mutex_lock(&curseg->curseg_mutex); ++ ++ /* 1) flush dirty nat caches */ ++ list_for_each_safe(cur, n, &nm_i->dirty_nat_entries) { ++ struct nat_entry *ne; ++ nid_t nid; ++ struct f2fs_nat_entry raw_ne; ++ int offset = -1; ++ block_t old_blkaddr, new_blkaddr; ++ ++ ne = list_entry(cur, struct nat_entry, list); ++ nid = nat_get_nid(ne); ++ ++ if (nat_get_blkaddr(ne) == NEW_ADDR) ++ continue; ++ if (flushed) ++ goto to_nat_page; ++ ++ /* if there is room for nat enries in curseg->sumpage */ ++ offset = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 1); ++ if (offset >= 0) { ++ raw_ne = nat_in_journal(sum, offset); ++ old_blkaddr = le32_to_cpu(raw_ne.block_addr); ++ goto flush_now; ++ } ++to_nat_page: ++ if (!page || (start_nid > nid || nid > end_nid)) { ++ if (page) { ++ f2fs_put_page(page, 1); ++ page = NULL; ++ } ++ start_nid = START_NID(nid); ++ end_nid = start_nid + NAT_ENTRY_PER_BLOCK - 1; ++ ++ /* ++ * get nat block with dirty flag, increased reference ++ * count, mapped and lock ++ */ ++ page = get_next_nat_page(sbi, start_nid); ++ nat_blk = page_address(page); ++ } ++ ++ BUG_ON(!nat_blk); ++ raw_ne = nat_blk->entries[nid - start_nid]; ++ old_blkaddr = le32_to_cpu(raw_ne.block_addr); ++flush_now: ++ new_blkaddr = nat_get_blkaddr(ne); ++ ++ raw_ne.ino = cpu_to_le32(nat_get_ino(ne)); ++ raw_ne.block_addr = cpu_to_le32(new_blkaddr); ++ raw_ne.version = nat_get_version(ne); ++ ++ if (offset < 0) { ++ nat_blk->entries[nid - start_nid] = raw_ne; ++ } else { ++ nat_in_journal(sum, offset) = raw_ne; ++ nid_in_journal(sum, offset) = cpu_to_le32(nid); ++ } ++ ++ if (nat_get_blkaddr(ne) == NULL_ADDR) { ++ write_lock(&nm_i->nat_tree_lock); ++ __del_from_nat_cache(nm_i, ne); ++ write_unlock(&nm_i->nat_tree_lock); ++ ++ /* We can reuse this freed nid at this point */ ++ add_free_nid(NM_I(sbi), nid); ++ } else { ++ write_lock(&nm_i->nat_tree_lock); ++ __clear_nat_cache_dirty(nm_i, ne); ++ ne->checkpointed = true; ++ write_unlock(&nm_i->nat_tree_lock); ++ } ++ } ++ if (!flushed) ++ mutex_unlock(&curseg->curseg_mutex); ++ ++ /* ++ * set block offset in cur_journal_segno1/2 ++ * where the last NAT update happened ++ */ ++ memcpy(nm_i->nat_upd_blkoff, ++ nm_i->lst_upd_blkoff, sizeof(int) * 3); ++ f2fs_put_page(page, 1); ++ ++ /* 2) shrink nat caches if necessary */ ++ try_to_free_nats(sbi, nm_i->nat_cnt - NM_WOUT_THRESHOLD); ++} ++ ++static int init_node_manager(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_super_block *sb_raw = F2FS_RAW_SUPER(sbi); ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ unsigned char *version_bitmap; ++ int i; ++ ++ nm_i->nat_blkaddr = le32_to_cpu(sb_raw->nat_blkaddr); ++ ++ /* segment_count_nat includes pair segment so divide to 2. */ ++ nm_i->nat_segs = le32_to_cpu(sb_raw->segment_count_nat) >> 1; ++ nm_i->nat_blocks = nm_i->nat_segs << ++ le32_to_cpu(sb_raw->log_blocks_per_seg); ++ nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nm_i->nat_blocks; ++ nm_i->fcnt = 0; ++ nm_i->nat_cnt = 0; ++ ++ INIT_LIST_HEAD(&nm_i->free_nid_list); ++ INIT_RADIX_TREE(&nm_i->nat_root, GFP_ATOMIC); ++ INIT_LIST_HEAD(&nm_i->nat_entries); ++ INIT_LIST_HEAD(&nm_i->dirty_nat_entries); ++ ++ mutex_init(&nm_i->build_lock); ++ spin_lock_init(&nm_i->free_nid_list_lock); ++ rwlock_init(&nm_i->nat_tree_lock); ++ ++ for (i = 0; i < 3; i++) { ++ nm_i->lst_upd_blkoff[i] = ++ le16_to_cpu(sbi->ckpt->nat_upd_blkoff[i]); ++ nm_i->nat_upd_blkoff[i] = ++ le16_to_cpu(sbi->ckpt->nat_upd_blkoff[i]); ++ } ++ ++ nm_i->written_valid_node_count = sbi->total_valid_node_count; ++ nm_i->written_valid_inode_count = sbi->total_valid_inode_count; ++ ++ nm_i->bitmap_size = __bitmap_size(sbi, NAT_BITMAP); ++ nm_i->init_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid); ++ nm_i->next_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid); ++ ++ nm_i->nat_bitmap = kzalloc(nm_i->bitmap_size, GFP_KERNEL); ++ if (!nm_i->nat_bitmap) ++ return -ENOMEM; ++ version_bitmap = __bitmap_ptr(sbi, NAT_BITMAP); ++ if (!version_bitmap) ++ return -EFAULT; ++ ++ /* copy version bitmap */ ++ memcpy(nm_i->nat_bitmap, version_bitmap, nm_i->bitmap_size); ++ return 0; ++} ++ ++int build_node_manager(struct f2fs_sb_info *sbi) ++{ ++ sbi->nm_info = kzalloc(sizeof(struct f2fs_nm_info), GFP_KERNEL); ++ if (!sbi->nm_info) ++ return -ENOMEM; ++ ++ if (init_node_manager(sbi)) ++ return -EINVAL; ++ ++ build_free_nids(sbi); ++ return 0; ++} ++ ++void destroy_node_manager(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_nm_info *nm_i = NM_I(sbi); ++ struct free_nid *i, *next_i; ++ struct nat_entry *natvec[NATVEC_SIZE]; ++ nid_t nid = 0; ++ unsigned int found; ++ ++ if (!nm_i) ++ return; ++ ++ /* destroy free nid list */ ++ spin_lock(&nm_i->free_nid_list_lock); ++ list_for_each_entry_safe(i, next_i, &nm_i->free_nid_list, list) { ++ BUG_ON(i->state == NID_ALLOC); ++ __del_from_free_nid_list(i); ++ nm_i->fcnt--; ++ } ++ BUG_ON(nm_i->fcnt); ++ spin_unlock(&nm_i->free_nid_list_lock); ++ ++ /* destroy nat cache */ ++ write_lock(&nm_i->nat_tree_lock); ++ while ((found = __gang_lookup_nat_cache(nm_i, ++ nid, NATVEC_SIZE, natvec))) { ++ unsigned idx; ++ for (idx = 0; idx < found; idx++) { ++ struct nat_entry *e = natvec[idx]; ++ nid = nat_get_nid(e) + 1; ++ __del_from_nat_cache(nm_i, e); ++ } ++ } ++ BUG_ON(nm_i->nat_cnt); ++ write_unlock(&nm_i->nat_tree_lock); ++ ++ kfree(nm_i->nat_bitmap); ++ sbi->nm_info = NULL; ++ kfree(nm_i); ++} ++ ++int create_node_manager_caches(void) ++{ ++ nat_entry_slab = f2fs_kmem_cache_create("nat_entry", ++ sizeof(struct nat_entry), NULL); ++ if (!nat_entry_slab) ++ return -ENOMEM; ++ ++ free_nid_slab = f2fs_kmem_cache_create("free_nid", ++ sizeof(struct free_nid), NULL); ++ if (!free_nid_slab) { ++ kmem_cache_destroy(nat_entry_slab); ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++void destroy_node_manager_caches(void) ++{ ++ kmem_cache_destroy(free_nid_slab); ++ kmem_cache_destroy(nat_entry_slab); ++} diff --git a/patches/linux-3.7-rc6/0104-f2fs-add-segment-operations.patch b/patches/linux-3.7-rc6/0104-f2fs-add-segment-operations.patch new file mode 100644 index 0000000..958a1e2 --- /dev/null +++ b/patches/linux-3.7-rc6/0104-f2fs-add-segment-operations.patch @@ -0,0 +1,1843 @@ +From 781489b7a9285a53af3273801286908a68d5ab50 Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:28:47 +0000 +Subject: [PATCH] f2fs: add segment operations + +This adds specific functions not only to manage dirty/free segments, SIT pages, +a cache for SIT entries, and summary entries, but also to allocate free blocks +and write three types of pages: data, node, and meta. + +- F2FS maintains three types of bitmaps in memory, which indicate free, prefree, + and dirty segments respectively. + +- The key information of an SIT entry consists of a segment number, the number + of valid blocks in the segment, a bitmap to identify there-in valid or invalid + blocks. + +- An SIT page is composed of a certain range of SIT entries, which is maintained + by the address space of meta_inode. + +- To cache SIT entries, a simple array is used. The index for the array is the + segment number. + +- A summary entry for data contains the parent node information. A summary entry + for node contains its node offset from the inode. + +- F2FS manages information about six active logs and those summary entries in + memory. Whenever one of them is changed, its summary entries are flushed to + its SIT page maintained by the address space of meta_inode. + +- This patch adds a default block allocation function which supports heap-based + allocation policy. + +- This patch adds core functions to write data, node, and meta pages. Since LFS + basically produces a series of sequential writes, F2FS merges sequential bios + with a single one as much as possible to reduce the IO scheduling overhead. + +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/f2fs/segment.c | 1795 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 1795 insertions(+) + create mode 100644 fs/f2fs/segment.c + +diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c +new file mode 100644 +index 0000000..57d0931 +--- /dev/null ++++ b/fs/f2fs/segment.c +@@ -0,0 +1,1795 @@ ++/** ++ * fs/f2fs/segment.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/fs.h> ++#include <linux/f2fs_fs.h> ++#include <linux/bio.h> ++#include <linux/blkdev.h> ++ ++#include "f2fs.h" ++#include "segment.h" ++#include "node.h" ++ ++static int need_to_flush(struct f2fs_sb_info *sbi) ++{ ++ unsigned int pages_per_sec = (1 << sbi->log_blocks_per_seg) * ++ sbi->segs_per_sec; ++ int node_secs = ((get_pages(sbi, F2FS_DIRTY_NODES) + pages_per_sec - 1) ++ >> sbi->log_blocks_per_seg) / sbi->segs_per_sec; ++ int dent_secs = ((get_pages(sbi, F2FS_DIRTY_DENTS) + pages_per_sec - 1) ++ >> sbi->log_blocks_per_seg) / sbi->segs_per_sec; ++ ++ if (sbi->por_doing) ++ return 0; ++ ++ if (free_sections(sbi) <= (node_secs + 2 * dent_secs + ++ reserved_sections(sbi))) ++ return 1; ++ return 0; ++} ++ ++/** ++ * This function balances dirty node and dentry pages. ++ * In addition, it controls garbage collection. ++ */ ++void f2fs_balance_fs(struct f2fs_sb_info *sbi) ++{ ++ struct writeback_control wbc = { ++ .sync_mode = WB_SYNC_ALL, ++ .nr_to_write = LONG_MAX, ++ .for_reclaim = 0, ++ }; ++ ++ if (sbi->por_doing) ++ return; ++ ++ /* ++ * We should do checkpoint when there are so many dirty node pages ++ * with enough free segments. After then, we should do GC. ++ */ ++ if (need_to_flush(sbi)) { ++ sync_dirty_dir_inodes(sbi); ++ sync_node_pages(sbi, 0, &wbc); ++ } ++ ++ if (has_not_enough_free_secs(sbi)) { ++ mutex_lock(&sbi->gc_mutex); ++ f2fs_gc(sbi, 1); ++ } ++} ++ ++static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, ++ enum dirty_type dirty_type) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ ++ /* need not be added */ ++ if (IS_CURSEG(sbi, segno)) ++ return; ++ ++ if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type])) ++ dirty_i->nr_dirty[dirty_type]++; ++ ++ if (dirty_type == DIRTY) { ++ struct seg_entry *sentry = get_seg_entry(sbi, segno); ++ dirty_type = sentry->type; ++ if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type])) ++ dirty_i->nr_dirty[dirty_type]++; ++ } ++} ++ ++static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, ++ enum dirty_type dirty_type) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ ++ if (test_and_clear_bit(segno, dirty_i->dirty_segmap[dirty_type])) ++ dirty_i->nr_dirty[dirty_type]--; ++ ++ if (dirty_type == DIRTY) { ++ struct seg_entry *sentry = get_seg_entry(sbi, segno); ++ dirty_type = sentry->type; ++ if (test_and_clear_bit(segno, ++ dirty_i->dirty_segmap[dirty_type])) ++ dirty_i->nr_dirty[dirty_type]--; ++ clear_bit(segno, dirty_i->victim_segmap[FG_GC]); ++ clear_bit(segno, dirty_i->victim_segmap[BG_GC]); ++ } ++} ++ ++/** ++ * Should not occur error such as -ENOMEM. ++ * Adding dirty entry into seglist is not critical operation. ++ * If a given segment is one of current working segments, it won't be added. ++ */ ++void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ unsigned short valid_blocks; ++ ++ if (segno == NULL_SEGNO || IS_CURSEG(sbi, segno)) ++ return; ++ ++ mutex_lock(&dirty_i->seglist_lock); ++ ++ valid_blocks = get_valid_blocks(sbi, segno, 0); ++ ++ if (valid_blocks == 0) { ++ __locate_dirty_segment(sbi, segno, PRE); ++ __remove_dirty_segment(sbi, segno, DIRTY); ++ } else if (valid_blocks < sbi->blocks_per_seg) { ++ __locate_dirty_segment(sbi, segno, DIRTY); ++ } else { ++ /* Recovery routine with SSR needs this */ ++ __remove_dirty_segment(sbi, segno, DIRTY); ++ } ++ ++ mutex_unlock(&dirty_i->seglist_lock); ++ return; ++} ++ ++/** ++ * Should call clear_prefree_segments after checkpoint is done. ++ */ ++static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ unsigned int segno, offset = 0; ++ unsigned int total_segs = TOTAL_SEGS(sbi); ++ ++ mutex_lock(&dirty_i->seglist_lock); ++ while (1) { ++ segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs, ++ offset); ++ if (segno >= total_segs) ++ break; ++ __set_test_and_free(sbi, segno); ++ offset = segno + 1; ++ } ++ mutex_unlock(&dirty_i->seglist_lock); ++} ++ ++void clear_prefree_segments(struct f2fs_sb_info *sbi) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ unsigned int segno, offset = 0; ++ unsigned int total_segs = TOTAL_SEGS(sbi); ++ ++ mutex_lock(&dirty_i->seglist_lock); ++ while (1) { ++ segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs, ++ offset); ++ if (segno >= total_segs) ++ break; ++ ++ offset = segno + 1; ++ if (test_and_clear_bit(segno, dirty_i->dirty_segmap[PRE])) ++ dirty_i->nr_dirty[PRE]--; ++ ++ /* Let's use trim */ ++ if (test_opt(sbi, DISCARD)) ++ blkdev_issue_discard(sbi->sb->s_bdev, ++ START_BLOCK(sbi, segno) << ++ sbi->log_sectors_per_block, ++ 1 << (sbi->log_sectors_per_block + ++ sbi->log_blocks_per_seg), ++ GFP_NOFS, 0); ++ } ++ mutex_unlock(&dirty_i->seglist_lock); ++} ++ ++static void __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ if (!__test_and_set_bit(segno, sit_i->dirty_sentries_bitmap)) ++ sit_i->dirty_sentries++; ++} ++ ++static void __set_sit_entry_type(struct f2fs_sb_info *sbi, int type, ++ unsigned int segno, int modified) ++{ ++ struct seg_entry *se = get_seg_entry(sbi, segno); ++ se->type = type; ++ if (modified) ++ __mark_sit_entry_dirty(sbi, segno); ++} ++ ++static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) ++{ ++ struct seg_entry *se; ++ unsigned int segno, offset; ++ long int new_vblocks; ++ ++ segno = GET_SEGNO(sbi, blkaddr); ++ ++ se = get_seg_entry(sbi, segno); ++ new_vblocks = se->valid_blocks + del; ++ offset = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) & (sbi->blocks_per_seg - 1); ++ ++ BUG_ON((new_vblocks >> (sizeof(unsigned short) << 3) || ++ (new_vblocks > sbi->blocks_per_seg))); ++ ++ se->valid_blocks = new_vblocks; ++ se->mtime = get_mtime(sbi); ++ SIT_I(sbi)->max_mtime = se->mtime; ++ ++ /* Update valid block bitmap */ ++ if (del > 0) { ++ if (f2fs_set_bit(offset, se->cur_valid_map)) ++ BUG(); ++ } else { ++ if (!f2fs_clear_bit(offset, se->cur_valid_map)) ++ BUG(); ++ } ++ if (!f2fs_test_bit(offset, se->ckpt_valid_map)) ++ se->ckpt_valid_blocks += del; ++ ++ __mark_sit_entry_dirty(sbi, segno); ++ ++ /* update total number of valid blocks to be written in ckpt area */ ++ SIT_I(sbi)->written_valid_blocks += del; ++ ++ if (sbi->segs_per_sec > 1) ++ get_sec_entry(sbi, segno)->valid_blocks += del; ++} ++ ++static void refresh_sit_entry(struct f2fs_sb_info *sbi, ++ block_t old_blkaddr, block_t new_blkaddr) ++{ ++ update_sit_entry(sbi, new_blkaddr, 1); ++ if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) ++ update_sit_entry(sbi, old_blkaddr, -1); ++} ++ ++void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) ++{ ++ unsigned int segno = GET_SEGNO(sbi, addr); ++ struct sit_info *sit_i = SIT_I(sbi); ++ ++ BUG_ON(addr == NULL_ADDR); ++ if (addr == NEW_ADDR) ++ return; ++ ++ /* add it into sit main buffer */ ++ mutex_lock(&sit_i->sentry_lock); ++ ++ update_sit_entry(sbi, addr, -1); ++ ++ /* add it into dirty seglist */ ++ locate_dirty_segment(sbi, segno); ++ ++ mutex_unlock(&sit_i->sentry_lock); ++} ++ ++/** ++ * This function should be resided under the curseg_mutex lock ++ */ ++static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, ++ struct f2fs_summary *sum, unsigned short offset) ++{ ++ struct curseg_info *curseg = CURSEG_I(sbi, type); ++ void *addr = curseg->sum_blk; ++ addr += offset * sizeof(struct f2fs_summary); ++ memcpy(addr, sum, sizeof(struct f2fs_summary)); ++ return; ++} ++ ++/** ++ * Calculate the number of current summary pages for writing ++ */ ++int npages_for_summary_flush(struct f2fs_sb_info *sbi) ++{ ++ int total_size_bytes = 0; ++ int valid_sum_count = 0; ++ int i, sum_space; ++ ++ for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { ++ if (sbi->ckpt->alloc_type[i] == SSR) ++ valid_sum_count += sbi->blocks_per_seg; ++ else ++ valid_sum_count += curseg_blkoff(sbi, i); ++ } ++ ++ total_size_bytes = valid_sum_count * (SUMMARY_SIZE + 1) ++ + sizeof(struct nat_journal) + 2 ++ + sizeof(struct sit_journal) + 2; ++ sum_space = PAGE_CACHE_SIZE - SUM_FOOTER_SIZE; ++ if (total_size_bytes < sum_space) ++ return 1; ++ else if (total_size_bytes < 2 * sum_space) ++ return 2; ++ return 3; ++} ++ ++/** ++ * Caller should put this summary page ++ */ ++struct page *get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno) ++{ ++ return get_meta_page(sbi, GET_SUM_BLOCK(sbi, segno)); ++} ++ ++static void write_sum_page(struct f2fs_sb_info *sbi, ++ struct f2fs_summary_block *sum_blk, block_t blk_addr) ++{ ++ struct page *page = grab_meta_page(sbi, blk_addr); ++ void *kaddr = page_address(page); ++ memcpy(kaddr, sum_blk, PAGE_CACHE_SIZE); ++ set_page_dirty(page); ++ f2fs_put_page(page, 1); ++} ++ ++static unsigned int check_prefree_segments(struct f2fs_sb_info *sbi, ++ int ofs_unit, int type) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ unsigned long *prefree_segmap = dirty_i->dirty_segmap[PRE]; ++ unsigned int segno, next_segno, i; ++ int ofs = 0; ++ ++ /* ++ * If there is not enough reserved sections, ++ * we should not reuse prefree segments. ++ */ ++ if (has_not_enough_free_secs(sbi)) ++ return NULL_SEGNO; ++ ++ /* ++ * NODE page should not reuse prefree segment, ++ * since those information is used for SPOR. ++ */ ++ if (IS_NODESEG(type)) ++ return NULL_SEGNO; ++next: ++ segno = find_next_bit(prefree_segmap, TOTAL_SEGS(sbi), ofs++); ++ ofs = ((segno / ofs_unit) * ofs_unit) + ofs_unit; ++ if (segno < TOTAL_SEGS(sbi)) { ++ /* skip intermediate segments in a section */ ++ if (segno % ofs_unit) ++ goto next; ++ ++ /* skip if whole section is not prefree */ ++ next_segno = find_next_zero_bit(prefree_segmap, ++ TOTAL_SEGS(sbi), segno + 1); ++ if (next_segno - segno < ofs_unit) ++ goto next; ++ ++ /* skip if whole section was not free at the last checkpoint */ ++ for (i = 0; i < ofs_unit; i++) ++ if (get_seg_entry(sbi, segno)->ckpt_valid_blocks) ++ goto next; ++ return segno; ++ } ++ return NULL_SEGNO; ++} ++ ++/** ++ * Find a new segment from the free segments bitmap to right order ++ * This function should be returned with success, otherwise BUG ++ */ ++static void get_new_segment(struct f2fs_sb_info *sbi, ++ unsigned int *newseg, bool new_sec, int dir) ++{ ++ struct free_segmap_info *free_i = FREE_I(sbi); ++ unsigned int total_secs = sbi->total_sections; ++ unsigned int segno, secno, zoneno; ++ unsigned int total_zones = sbi->total_sections / sbi->secs_per_zone; ++ unsigned int hint = *newseg / sbi->segs_per_sec; ++ unsigned int old_zoneno = GET_ZONENO_FROM_SEGNO(sbi, *newseg); ++ unsigned int left_start = hint; ++ bool init = true; ++ int go_left = 0; ++ int i; ++ ++ write_lock(&free_i->segmap_lock); ++ ++ if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) { ++ segno = find_next_zero_bit(free_i->free_segmap, ++ TOTAL_SEGS(sbi), *newseg + 1); ++ if (segno < TOTAL_SEGS(sbi)) ++ goto got_it; ++ } ++find_other_zone: ++ secno = find_next_zero_bit(free_i->free_secmap, total_secs, hint); ++ if (secno >= total_secs) { ++ if (dir == ALLOC_RIGHT) { ++ secno = find_next_zero_bit(free_i->free_secmap, ++ total_secs, 0); ++ BUG_ON(secno >= total_secs); ++ } else { ++ go_left = 1; ++ left_start = hint - 1; ++ } ++ } ++ if (go_left == 0) ++ goto skip_left; ++ ++ while (test_bit(left_start, free_i->free_secmap)) { ++ if (left_start > 0) { ++ left_start--; ++ continue; ++ } ++ left_start = find_next_zero_bit(free_i->free_secmap, ++ total_secs, 0); ++ BUG_ON(left_start >= total_secs); ++ break; ++ } ++ secno = left_start; ++skip_left: ++ hint = secno; ++ segno = secno * sbi->segs_per_sec; ++ zoneno = secno / sbi->secs_per_zone; ++ ++ /* give up on finding another zone */ ++ if (!init) ++ goto got_it; ++ if (sbi->secs_per_zone == 1) ++ goto got_it; ++ if (zoneno == old_zoneno) ++ goto got_it; ++ if (dir == ALLOC_LEFT) { ++ if (!go_left && zoneno + 1 >= total_zones) ++ goto got_it; ++ if (go_left && zoneno == 0) ++ goto got_it; ++ } ++ for (i = 0; i < NR_CURSEG_TYPE; i++) ++ if (CURSEG_I(sbi, i)->zone == zoneno) ++ break; ++ ++ if (i < NR_CURSEG_TYPE) { ++ /* zone is in user, try another */ ++ if (go_left) ++ hint = zoneno * sbi->secs_per_zone - 1; ++ else if (zoneno + 1 >= total_zones) ++ hint = 0; ++ else ++ hint = (zoneno + 1) * sbi->secs_per_zone; ++ init = false; ++ goto find_other_zone; ++ } ++got_it: ++ /* set it as dirty segment in free segmap */ ++ BUG_ON(test_bit(segno, free_i->free_segmap)); ++ __set_inuse(sbi, segno); ++ *newseg = segno; ++ write_unlock(&free_i->segmap_lock); ++} ++ ++static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) ++{ ++ struct curseg_info *curseg = CURSEG_I(sbi, type); ++ struct summary_footer *sum_footer; ++ ++ curseg->segno = curseg->next_segno; ++ curseg->zone = GET_ZONENO_FROM_SEGNO(sbi, curseg->segno); ++ curseg->next_blkoff = 0; ++ curseg->next_segno = NULL_SEGNO; ++ ++ sum_footer = &(curseg->sum_blk->footer); ++ memset(sum_footer, 0, sizeof(struct summary_footer)); ++ if (IS_DATASEG(type)) ++ SET_SUM_TYPE(sum_footer, SUM_TYPE_DATA); ++ if (IS_NODESEG(type)) ++ SET_SUM_TYPE(sum_footer, SUM_TYPE_NODE); ++ __set_sit_entry_type(sbi, type, curseg->segno, modified); ++} ++ ++/** ++ * Allocate a current working segment. ++ * This function always allocates a free segment in LFS manner. ++ */ ++static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec) ++{ ++ struct curseg_info *curseg = CURSEG_I(sbi, type); ++ unsigned int segno = curseg->segno; ++ int dir = ALLOC_LEFT; ++ ++ write_sum_page(sbi, curseg->sum_blk, ++ GET_SUM_BLOCK(sbi, curseg->segno)); ++ if (type == CURSEG_WARM_DATA || type == CURSEG_COLD_DATA) ++ dir = ALLOC_RIGHT; ++ ++ if (test_opt(sbi, NOHEAP)) ++ dir = ALLOC_RIGHT; ++ ++ get_new_segment(sbi, &segno, new_sec, dir); ++ curseg->next_segno = segno; ++ reset_curseg(sbi, type, 1); ++ curseg->alloc_type = LFS; ++} ++ ++static void __next_free_blkoff(struct f2fs_sb_info *sbi, ++ struct curseg_info *seg, block_t start) ++{ ++ struct seg_entry *se = get_seg_entry(sbi, seg->segno); ++ block_t ofs; ++ for (ofs = start; ofs < sbi->blocks_per_seg; ofs++) { ++ if (!f2fs_test_bit(ofs, se->ckpt_valid_map) ++ && !f2fs_test_bit(ofs, se->cur_valid_map)) ++ break; ++ } ++ seg->next_blkoff = ofs; ++} ++ ++/** ++ * If a segment is written by LFS manner, next block offset is just obtained ++ * by increasing the current block offset. However, if a segment is written by ++ * SSR manner, next block offset obtained by calling __next_free_blkoff ++ */ ++static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, ++ struct curseg_info *seg) ++{ ++ if (seg->alloc_type == SSR) ++ __next_free_blkoff(sbi, seg, seg->next_blkoff + 1); ++ else ++ seg->next_blkoff++; ++} ++ ++/** ++ * This function always allocates a used segment (from dirty seglist) by SSR ++ * manner, so it should recover the existing segment information of valid blocks ++ */ ++static void change_curseg(struct f2fs_sb_info *sbi, int type, bool reuse) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ struct curseg_info *curseg = CURSEG_I(sbi, type); ++ unsigned int new_segno = curseg->next_segno; ++ struct f2fs_summary_block *sum_node; ++ struct page *sum_page; ++ ++ write_sum_page(sbi, curseg->sum_blk, ++ GET_SUM_BLOCK(sbi, curseg->segno)); ++ __set_test_and_inuse(sbi, new_segno); ++ ++ mutex_lock(&dirty_i->seglist_lock); ++ __remove_dirty_segment(sbi, new_segno, PRE); ++ __remove_dirty_segment(sbi, new_segno, DIRTY); ++ mutex_unlock(&dirty_i->seglist_lock); ++ ++ reset_curseg(sbi, type, 1); ++ curseg->alloc_type = SSR; ++ __next_free_blkoff(sbi, curseg, 0); ++ ++ if (reuse) { ++ sum_page = get_sum_page(sbi, new_segno); ++ sum_node = (struct f2fs_summary_block *)page_address(sum_page); ++ memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE); ++ f2fs_put_page(sum_page, 1); ++ } ++} ++ ++/* ++ * flush out current segment and replace it with new segment ++ * This function should be returned with success, otherwise BUG ++ */ ++static void allocate_segment_by_default(struct f2fs_sb_info *sbi, ++ int type, bool force) ++{ ++ struct curseg_info *curseg = CURSEG_I(sbi, type); ++ unsigned int ofs_unit; ++ ++ if (force) { ++ new_curseg(sbi, type, true); ++ goto out; ++ } ++ ++ ofs_unit = need_SSR(sbi) ? 1 : sbi->segs_per_sec; ++ curseg->next_segno = check_prefree_segments(sbi, ofs_unit, type); ++ ++ if (curseg->next_segno != NULL_SEGNO) ++ change_curseg(sbi, type, false); ++ else if (type == CURSEG_WARM_NODE) ++ new_curseg(sbi, type, false); ++ else if (need_SSR(sbi) && IS_NEXT_SEG(sbi, curseg, type)) ++ change_curseg(sbi, type, true); ++ else ++ new_curseg(sbi, type, false); ++out: ++ sbi->segment_count[curseg->alloc_type]++; ++} ++ ++void allocate_new_segments(struct f2fs_sb_info *sbi) ++{ ++ struct curseg_info *curseg; ++ unsigned int old_curseg; ++ int i; ++ ++ for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { ++ curseg = CURSEG_I(sbi, i); ++ old_curseg = curseg->segno; ++ SIT_I(sbi)->s_ops->allocate_segment(sbi, i, true); ++ locate_dirty_segment(sbi, old_curseg); ++ } ++} ++ ++static const struct segment_allocation default_salloc_ops = { ++ .allocate_segment = allocate_segment_by_default, ++}; ++ ++static void f2fs_end_io_write(struct bio *bio, int err) ++{ ++ const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); ++ struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; ++ struct bio_private *p = bio->bi_private; ++ ++ do { ++ struct page *page = bvec->bv_page; ++ ++ if (--bvec >= bio->bi_io_vec) ++ prefetchw(&bvec->bv_page->flags); ++ if (!uptodate) { ++ SetPageError(page); ++ if (page->mapping) ++ set_bit(AS_EIO, &page->mapping->flags); ++ p->sbi->ckpt->ckpt_flags |= CP_ERROR_FLAG; ++ set_page_dirty(page); ++ } ++ end_page_writeback(page); ++ dec_page_count(p->sbi, F2FS_WRITEBACK); ++ } while (bvec >= bio->bi_io_vec); ++ ++ if (p->is_sync) ++ complete(p->wait); ++ kfree(p); ++ bio_put(bio); ++} ++ ++struct bio *f2fs_bio_alloc(struct block_device *bdev, sector_t first_sector, ++ int nr_vecs, gfp_t gfp_flags) ++{ ++ struct bio *bio; ++repeat: ++ /* allocate new bio */ ++ bio = bio_alloc(gfp_flags, nr_vecs); ++ ++ if (bio == NULL && (current->flags & PF_MEMALLOC)) { ++ while (!bio && (nr_vecs /= 2)) ++ bio = bio_alloc(gfp_flags, nr_vecs); ++ } ++ if (bio) { ++ bio->bi_bdev = bdev; ++ bio->bi_sector = first_sector; ++retry: ++ bio->bi_private = kmalloc(sizeof(struct bio_private), ++ GFP_NOFS | __GFP_HIGH); ++ if (!bio->bi_private) { ++ cond_resched(); ++ goto retry; ++ } ++ } ++ if (bio == NULL) { ++ cond_resched(); ++ goto repeat; ++ } ++ return bio; ++} ++ ++static void do_submit_bio(struct f2fs_sb_info *sbi, ++ enum page_type type, bool sync) ++{ ++ int rw = sync ? WRITE_SYNC : WRITE; ++ enum page_type btype = type > META ? META : type; ++ ++ if (type >= META_FLUSH) ++ rw = WRITE_FLUSH_FUA; ++ ++ if (sbi->bio[btype]) { ++ struct bio_private *p = sbi->bio[btype]->bi_private; ++ p->sbi = sbi; ++ sbi->bio[btype]->bi_end_io = f2fs_end_io_write; ++ if (type == META_FLUSH) { ++ DECLARE_COMPLETION_ONSTACK(wait); ++ p->is_sync = true; ++ p->wait = &wait; ++ submit_bio(rw, sbi->bio[btype]); ++ wait_for_completion(&wait); ++ } else { ++ p->is_sync = false; ++ submit_bio(rw, sbi->bio[btype]); ++ } ++ sbi->bio[btype] = NULL; ++ } ++} ++ ++void f2fs_submit_bio(struct f2fs_sb_info *sbi, enum page_type type, bool sync) ++{ ++ down_write(&sbi->bio_sem); ++ do_submit_bio(sbi, type, sync); ++ up_write(&sbi->bio_sem); ++} ++ ++static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page, ++ block_t blk_addr, enum page_type type) ++{ ++ struct block_device *bdev = sbi->sb->s_bdev; ++ ++ verify_block_addr(sbi, blk_addr); ++ ++ down_write(&sbi->bio_sem); ++ ++ inc_page_count(sbi, F2FS_WRITEBACK); ++ ++ if (sbi->bio[type] && sbi->last_block_in_bio[type] != blk_addr - 1) ++ do_submit_bio(sbi, type, false); ++alloc_new: ++ if (sbi->bio[type] == NULL) ++ sbi->bio[type] = f2fs_bio_alloc(bdev, ++ blk_addr << (sbi->log_blocksize - 9), ++ bio_get_nr_vecs(bdev), GFP_NOFS | __GFP_HIGH); ++ ++ if (bio_add_page(sbi->bio[type], page, PAGE_CACHE_SIZE, 0) < ++ PAGE_CACHE_SIZE) { ++ do_submit_bio(sbi, type, false); ++ goto alloc_new; ++ } ++ ++ sbi->last_block_in_bio[type] = blk_addr; ++ ++ up_write(&sbi->bio_sem); ++} ++ ++static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type) ++{ ++ struct curseg_info *curseg = CURSEG_I(sbi, type); ++ if (curseg->next_blkoff < sbi->blocks_per_seg) ++ return true; ++ return false; ++} ++ ++static int __get_segment_type_2(struct page *page, enum page_type p_type) ++{ ++ if (p_type == DATA) ++ return CURSEG_HOT_DATA; ++ else ++ return CURSEG_HOT_NODE; ++} ++ ++static int __get_segment_type_4(struct page *page, enum page_type p_type) ++{ ++ if (p_type == DATA) { ++ struct inode *inode = page->mapping->host; ++ ++ if (S_ISDIR(inode->i_mode)) ++ return CURSEG_HOT_DATA; ++ else ++ return CURSEG_COLD_DATA; ++ } else { ++ if (IS_DNODE(page) && !is_cold_node(page)) ++ return CURSEG_HOT_NODE; ++ else ++ return CURSEG_COLD_NODE; ++ } ++} ++ ++static int __get_segment_type_6(struct page *page, enum page_type p_type) ++{ ++ if (p_type == DATA) { ++ struct inode *inode = page->mapping->host; ++ ++ if (S_ISDIR(inode->i_mode)) ++ return CURSEG_HOT_DATA; ++ else if (is_cold_data(page) || is_cold_file(inode)) ++ return CURSEG_COLD_DATA; ++ else ++ return CURSEG_WARM_DATA; ++ } else { ++ if (IS_DNODE(page)) ++ return is_cold_node(page) ? CURSEG_WARM_NODE : ++ CURSEG_HOT_NODE; ++ else ++ return CURSEG_COLD_NODE; ++ } ++} ++ ++static int __get_segment_type(struct page *page, enum page_type p_type) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); ++ switch (sbi->active_logs) { ++ case 2: ++ return __get_segment_type_2(page, p_type); ++ case 4: ++ return __get_segment_type_4(page, p_type); ++ case 6: ++ return __get_segment_type_6(page, p_type); ++ default: ++ BUG(); ++ } ++} ++ ++static void do_write_page(struct f2fs_sb_info *sbi, struct page *page, ++ block_t old_blkaddr, block_t *new_blkaddr, ++ struct f2fs_summary *sum, enum page_type p_type) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ struct curseg_info *curseg; ++ unsigned int old_cursegno; ++ int type; ++ ++ type = __get_segment_type(page, p_type); ++ curseg = CURSEG_I(sbi, type); ++ ++ mutex_lock(&curseg->curseg_mutex); ++ ++ *new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); ++ old_cursegno = curseg->segno; ++ ++ /* ++ * __add_sum_entry should be resided under the curseg_mutex ++ * because, this function updates a summary entry in the ++ * current summary block. ++ */ ++ __add_sum_entry(sbi, type, sum, curseg->next_blkoff); ++ ++ mutex_lock(&sit_i->sentry_lock); ++ __refresh_next_blkoff(sbi, curseg); ++ sbi->block_count[curseg->alloc_type]++; ++ ++ /* ++ * SIT information should be updated before segment allocation, ++ * since SSR needs latest valid block information. ++ */ ++ refresh_sit_entry(sbi, old_blkaddr, *new_blkaddr); ++ ++ if (!__has_curseg_space(sbi, type)) ++ sit_i->s_ops->allocate_segment(sbi, type, false); ++ ++ locate_dirty_segment(sbi, old_cursegno); ++ locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); ++ mutex_unlock(&sit_i->sentry_lock); ++ ++ if (p_type == NODE) ++ fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg)); ++ ++ /* writeout dirty page into bdev */ ++ submit_write_page(sbi, page, *new_blkaddr, p_type); ++ ++ mutex_unlock(&curseg->curseg_mutex); ++} ++ ++int write_meta_page(struct f2fs_sb_info *sbi, struct page *page, ++ struct writeback_control *wbc) ++{ ++ if (wbc->for_reclaim) ++ return AOP_WRITEPAGE_ACTIVATE; ++ ++ set_page_writeback(page); ++ submit_write_page(sbi, page, page->index, META); ++ return 0; ++} ++ ++void write_node_page(struct f2fs_sb_info *sbi, struct page *page, ++ unsigned int nid, block_t old_blkaddr, block_t *new_blkaddr) ++{ ++ struct f2fs_summary sum; ++ set_summary(&sum, nid, 0, 0); ++ do_write_page(sbi, page, old_blkaddr, new_blkaddr, &sum, NODE); ++} ++ ++void write_data_page(struct inode *inode, struct page *page, ++ struct dnode_of_data *dn, block_t old_blkaddr, ++ block_t *new_blkaddr) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct f2fs_summary sum; ++ struct node_info ni; ++ ++ BUG_ON(old_blkaddr == NULL_ADDR); ++ get_node_info(sbi, dn->nid, &ni); ++ set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); ++ ++ do_write_page(sbi, page, old_blkaddr, ++ new_blkaddr, &sum, DATA); ++} ++ ++void rewrite_data_page(struct f2fs_sb_info *sbi, struct page *page, ++ block_t old_blk_addr) ++{ ++ submit_write_page(sbi, page, old_blk_addr, DATA); ++} ++ ++void recover_data_page(struct f2fs_sb_info *sbi, ++ struct page *page, struct f2fs_summary *sum, ++ block_t old_blkaddr, block_t new_blkaddr) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ struct curseg_info *curseg; ++ unsigned int segno, old_cursegno; ++ struct seg_entry *se; ++ int type; ++ ++ segno = GET_SEGNO(sbi, new_blkaddr); ++ se = get_seg_entry(sbi, segno); ++ type = se->type; ++ ++ if (se->valid_blocks == 0 && !IS_CURSEG(sbi, segno)) { ++ if (old_blkaddr == NULL_ADDR) ++ type = CURSEG_COLD_DATA; ++ else ++ type = CURSEG_WARM_DATA; ++ } ++ curseg = CURSEG_I(sbi, type); ++ ++ mutex_lock(&curseg->curseg_mutex); ++ mutex_lock(&sit_i->sentry_lock); ++ ++ old_cursegno = curseg->segno; ++ ++ /* change the current segment */ ++ if (segno != curseg->segno) { ++ curseg->next_segno = segno; ++ change_curseg(sbi, type, true); ++ } ++ ++ curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) & ++ (sbi->blocks_per_seg - 1); ++ __add_sum_entry(sbi, type, sum, curseg->next_blkoff); ++ ++ refresh_sit_entry(sbi, old_blkaddr, new_blkaddr); ++ ++ locate_dirty_segment(sbi, old_cursegno); ++ locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); ++ ++ mutex_unlock(&sit_i->sentry_lock); ++ mutex_unlock(&curseg->curseg_mutex); ++} ++ ++void rewrite_node_page(struct f2fs_sb_info *sbi, ++ struct page *page, struct f2fs_summary *sum, ++ block_t old_blkaddr, block_t new_blkaddr) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ int type = CURSEG_WARM_NODE; ++ struct curseg_info *curseg; ++ unsigned int segno, old_cursegno; ++ block_t next_blkaddr = next_blkaddr_of_node(page); ++ unsigned int next_segno = GET_SEGNO(sbi, next_blkaddr); ++ ++ curseg = CURSEG_I(sbi, type); ++ ++ mutex_lock(&curseg->curseg_mutex); ++ mutex_lock(&sit_i->sentry_lock); ++ ++ segno = GET_SEGNO(sbi, new_blkaddr); ++ old_cursegno = curseg->segno; ++ ++ /* change the current segment */ ++ if (segno != curseg->segno) { ++ curseg->next_segno = segno; ++ change_curseg(sbi, type, true); ++ } ++ curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) & ++ (sbi->blocks_per_seg - 1); ++ __add_sum_entry(sbi, type, sum, curseg->next_blkoff); ++ ++ /* change the current log to the next block addr in advance */ ++ if (next_segno != segno) { ++ curseg->next_segno = next_segno; ++ change_curseg(sbi, type, true); ++ } ++ curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, next_blkaddr) & ++ (sbi->blocks_per_seg - 1); ++ ++ /* rewrite node page */ ++ set_page_writeback(page); ++ submit_write_page(sbi, page, new_blkaddr, NODE); ++ f2fs_submit_bio(sbi, NODE, true); ++ refresh_sit_entry(sbi, old_blkaddr, new_blkaddr); ++ ++ locate_dirty_segment(sbi, old_cursegno); ++ locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); ++ ++ mutex_unlock(&sit_i->sentry_lock); ++ mutex_unlock(&curseg->curseg_mutex); ++} ++ ++static int read_compacted_summaries(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); ++ struct curseg_info *seg_i; ++ unsigned char *kaddr; ++ struct page *page; ++ block_t start; ++ int i, j, offset; ++ ++ start = start_sum_block(sbi); ++ ++ page = get_meta_page(sbi, start++); ++ kaddr = (unsigned char *)page_address(page); ++ ++ /* Step 1: restore nat cache */ ++ seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); ++ memcpy(&seg_i->sum_blk->n_nats, kaddr, SUM_JOURNAL_SIZE); ++ ++ /* Step 2: restore sit cache */ ++ seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); ++ memcpy(&seg_i->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE, ++ SUM_JOURNAL_SIZE); ++ offset = 2 * SUM_JOURNAL_SIZE; ++ ++ /* Step 3: restore summary entries */ ++ for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { ++ unsigned short blk_off; ++ unsigned int segno; ++ ++ seg_i = CURSEG_I(sbi, i); ++ segno = le32_to_cpu(ckpt->cur_data_segno[i]); ++ blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]); ++ seg_i->next_segno = segno; ++ reset_curseg(sbi, i, 0); ++ seg_i->alloc_type = ckpt->alloc_type[i]; ++ seg_i->next_blkoff = blk_off; ++ ++ if (seg_i->alloc_type == SSR) ++ blk_off = sbi->blocks_per_seg; ++ ++ for (j = 0; j < blk_off; j++) { ++ struct f2fs_summary *s; ++ s = (struct f2fs_summary *)(kaddr + offset); ++ seg_i->sum_blk->entries[j] = *s; ++ offset += SUMMARY_SIZE; ++ if (offset + SUMMARY_SIZE <= PAGE_CACHE_SIZE - ++ SUM_FOOTER_SIZE) ++ continue; ++ ++ f2fs_put_page(page, 1); ++ page = NULL; ++ ++ page = get_meta_page(sbi, start++); ++ kaddr = (unsigned char *)page_address(page); ++ offset = 0; ++ } ++ } ++ f2fs_put_page(page, 1); ++ return 0; ++} ++ ++static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) ++{ ++ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); ++ struct f2fs_summary_block *sum; ++ struct curseg_info *curseg; ++ struct page *new; ++ unsigned short blk_off; ++ unsigned int segno = 0; ++ block_t blk_addr = 0; ++ ++ /* get segment number and block addr */ ++ if (IS_DATASEG(type)) { ++ segno = le32_to_cpu(ckpt->cur_data_segno[type]); ++ blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - ++ CURSEG_HOT_DATA]); ++ if (ckpt->ckpt_flags & CP_UMOUNT_FLAG) ++ blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type); ++ else ++ blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type); ++ } else { ++ segno = le32_to_cpu(ckpt->cur_node_segno[type - ++ CURSEG_HOT_NODE]); ++ blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type - ++ CURSEG_HOT_NODE]); ++ if (ckpt->ckpt_flags & CP_UMOUNT_FLAG) ++ blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, ++ type - CURSEG_HOT_NODE); ++ else ++ blk_addr = GET_SUM_BLOCK(sbi, segno); ++ } ++ ++ new = get_meta_page(sbi, blk_addr); ++ sum = (struct f2fs_summary_block *)page_address(new); ++ ++ if (IS_NODESEG(type)) { ++ if (ckpt->ckpt_flags & CP_UMOUNT_FLAG) { ++ struct f2fs_summary *ns = &sum->entries[0]; ++ int i; ++ for (i = 0; i < sbi->blocks_per_seg; i++, ns++) { ++ ns->version = 0; ++ ns->ofs_in_node = 0; ++ } ++ } else { ++ if (restore_node_summary(sbi, segno, sum)) { ++ f2fs_put_page(new, 1); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ /* set uncompleted segment to curseg */ ++ curseg = CURSEG_I(sbi, type); ++ mutex_lock(&curseg->curseg_mutex); ++ memcpy(curseg->sum_blk, sum, PAGE_CACHE_SIZE); ++ curseg->next_segno = segno; ++ reset_curseg(sbi, type, 0); ++ curseg->alloc_type = ckpt->alloc_type[type]; ++ curseg->next_blkoff = blk_off; ++ mutex_unlock(&curseg->curseg_mutex); ++ f2fs_put_page(new, 1); ++ return 0; ++} ++ ++static int restore_curseg_summaries(struct f2fs_sb_info *sbi) ++{ ++ int type = CURSEG_HOT_DATA; ++ ++ if (sbi->ckpt->ckpt_flags & CP_COMPACT_SUM_FLAG) { ++ /* restore for compacted data summary */ ++ if (read_compacted_summaries(sbi)) ++ return -EINVAL; ++ type = CURSEG_HOT_NODE; ++ } ++ ++ for (; type <= CURSEG_COLD_NODE; type++) ++ if (read_normal_summaries(sbi, type)) ++ return -EINVAL; ++ return 0; ++} ++ ++static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr) ++{ ++ struct page *page; ++ unsigned char *kaddr; ++ struct f2fs_summary *summary; ++ struct curseg_info *seg_i; ++ int written_size = 0; ++ int i, j; ++ ++ page = grab_meta_page(sbi, blkaddr++); ++ kaddr = (unsigned char *)page_address(page); ++ ++ /* Step 1: write nat cache */ ++ seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); ++ memcpy(kaddr, &seg_i->sum_blk->n_nats, SUM_JOURNAL_SIZE); ++ written_size += SUM_JOURNAL_SIZE; ++ ++ /* Step 2: write sit cache */ ++ seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); ++ memcpy(kaddr + written_size, &seg_i->sum_blk->n_sits, ++ SUM_JOURNAL_SIZE); ++ written_size += SUM_JOURNAL_SIZE; ++ ++ set_page_dirty(page); ++ ++ /* Step 3: write summary entries */ ++ for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { ++ unsigned short blkoff; ++ seg_i = CURSEG_I(sbi, i); ++ if (sbi->ckpt->alloc_type[i] == SSR) ++ blkoff = sbi->blocks_per_seg; ++ else ++ blkoff = curseg_blkoff(sbi, i); ++ ++ for (j = 0; j < blkoff; j++) { ++ if (!page) { ++ page = grab_meta_page(sbi, blkaddr++); ++ kaddr = (unsigned char *)page_address(page); ++ written_size = 0; ++ } ++ summary = (struct f2fs_summary *)(kaddr + written_size); ++ *summary = seg_i->sum_blk->entries[j]; ++ written_size += SUMMARY_SIZE; ++ set_page_dirty(page); ++ ++ if (written_size + SUMMARY_SIZE <= PAGE_CACHE_SIZE - ++ SUM_FOOTER_SIZE) ++ continue; ++ ++ f2fs_put_page(page, 1); ++ page = NULL; ++ } ++ } ++ if (page) ++ f2fs_put_page(page, 1); ++} ++ ++static void write_normal_summaries(struct f2fs_sb_info *sbi, ++ block_t blkaddr, int type) ++{ ++ int i, end; ++ if (IS_DATASEG(type)) ++ end = type + NR_CURSEG_DATA_TYPE; ++ else ++ end = type + NR_CURSEG_NODE_TYPE; ++ ++ for (i = type; i < end; i++) { ++ struct curseg_info *sum = CURSEG_I(sbi, i); ++ mutex_lock(&sum->curseg_mutex); ++ write_sum_page(sbi, sum->sum_blk, blkaddr + (i - type)); ++ mutex_unlock(&sum->curseg_mutex); ++ } ++} ++ ++void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk) ++{ ++ if (sbi->ckpt->ckpt_flags & CP_COMPACT_SUM_FLAG) ++ write_compacted_summaries(sbi, start_blk); ++ else ++ write_normal_summaries(sbi, start_blk, CURSEG_HOT_DATA); ++} ++ ++void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk) ++{ ++ if (sbi->ckpt->ckpt_flags & CP_UMOUNT_FLAG) ++ write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); ++ return; ++} ++ ++int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type, ++ unsigned int val, int alloc) ++{ ++ int i; ++ ++ if (type == NAT_JOURNAL) { ++ for (i = 0; i < nats_in_cursum(sum); i++) { ++ if (le32_to_cpu(nid_in_journal(sum, i)) == val) ++ return i; ++ } ++ if (alloc && nats_in_cursum(sum) < NAT_JOURNAL_ENTRIES) ++ return update_nats_in_cursum(sum, 1); ++ } else if (type == SIT_JOURNAL) { ++ for (i = 0; i < sits_in_cursum(sum); i++) ++ if (le32_to_cpu(segno_in_journal(sum, i)) == val) ++ return i; ++ if (alloc && sits_in_cursum(sum) < SIT_JOURNAL_ENTRIES) ++ return update_sits_in_cursum(sum, 1); ++ } ++ return -1; ++} ++ ++static struct page *get_current_sit_page(struct f2fs_sb_info *sbi, ++ unsigned int segno) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno); ++ block_t blk_addr = sit_i->sit_base_addr + offset; ++ ++ check_seg_range(sbi, segno); ++ ++ /* calculate sit block address */ ++ if (f2fs_test_bit(offset, sit_i->sit_bitmap)) ++ blk_addr += sit_i->sit_blocks; ++ ++ return get_meta_page(sbi, blk_addr); ++} ++ ++static struct page *get_next_sit_page(struct f2fs_sb_info *sbi, ++ unsigned int start) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ struct page *src_page, *dst_page; ++ pgoff_t src_off, dst_off; ++ void *src_addr, *dst_addr; ++ ++ src_off = current_sit_addr(sbi, start); ++ dst_off = next_sit_addr(sbi, src_off); ++ ++ /* get current sit block page without lock */ ++ src_page = get_meta_page(sbi, src_off); ++ dst_page = grab_meta_page(sbi, dst_off); ++ BUG_ON(PageDirty(src_page)); ++ ++ src_addr = page_address(src_page); ++ dst_addr = page_address(dst_page); ++ memcpy(dst_addr, src_addr, PAGE_CACHE_SIZE); ++ ++ set_page_dirty(dst_page); ++ f2fs_put_page(src_page, 1); ++ ++ set_to_next_sit(sit_i, start); ++ ++ return dst_page; ++} ++ ++static bool flush_sits_in_journal(struct f2fs_sb_info *sbi) ++{ ++ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); ++ struct f2fs_summary_block *sum = curseg->sum_blk; ++ int i; ++ ++ /* ++ * If the journal area in the current summary is full of sit entries, ++ * all the sit entries will be flushed. Otherwise the sit entries ++ * are not able to replace with newly hot sit entries. ++ */ ++ if (sits_in_cursum(sum) >= SIT_JOURNAL_ENTRIES) { ++ for (i = sits_in_cursum(sum) - 1; i >= 0; i--) { ++ unsigned int segno; ++ segno = le32_to_cpu(segno_in_journal(sum, i)); ++ __mark_sit_entry_dirty(sbi, segno); ++ } ++ update_sits_in_cursum(sum, -sits_in_cursum(sum)); ++ return 1; ++ } ++ return 0; ++} ++ ++/** ++ * CP calls this function, which flushes SIT entries including sit_journal, ++ * and moves prefree segs to free segs. ++ */ ++void flush_sit_entries(struct f2fs_sb_info *sbi) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ unsigned long *bitmap = sit_i->dirty_sentries_bitmap; ++ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); ++ struct f2fs_summary_block *sum = curseg->sum_blk; ++ unsigned long nsegs = TOTAL_SEGS(sbi); ++ struct page *page = NULL; ++ struct f2fs_sit_block *raw_sit = NULL; ++ unsigned int start = 0, end = 0; ++ unsigned int segno = -1; ++ bool flushed; ++ ++ mutex_lock(&curseg->curseg_mutex); ++ mutex_lock(&sit_i->sentry_lock); ++ ++ /* ++ * "flushed" indicates whether sit entries in journal are flushed ++ * to the SIT area or not. ++ */ ++ flushed = flush_sits_in_journal(sbi); ++ ++ while ((segno = find_next_bit(bitmap, nsegs, segno + 1)) < nsegs) { ++ struct seg_entry *se = get_seg_entry(sbi, segno); ++ int sit_offset, offset; ++ ++ sit_offset = SIT_ENTRY_OFFSET(sit_i, segno); ++ ++ if (flushed) ++ goto to_sit_page; ++ ++ offset = lookup_journal_in_cursum(sum, SIT_JOURNAL, segno, 1); ++ if (offset >= 0) { ++ segno_in_journal(sum, offset) = cpu_to_le32(segno); ++ seg_info_to_raw_sit(se, &sit_in_journal(sum, offset)); ++ goto flush_done; ++ } ++to_sit_page: ++ if (!page || (start > segno) || (segno > end)) { ++ if (page) { ++ f2fs_put_page(page, 1); ++ page = NULL; ++ } ++ ++ start = START_SEGNO(sit_i, segno); ++ end = start + SIT_ENTRY_PER_BLOCK - 1; ++ ++ /* read sit block that will be updated */ ++ page = get_next_sit_page(sbi, start); ++ raw_sit = page_address(page); ++ } ++ ++ /* udpate entry in SIT block */ ++ seg_info_to_raw_sit(se, &raw_sit->entries[sit_offset]); ++flush_done: ++ __clear_bit(segno, bitmap); ++ sit_i->dirty_sentries--; ++ } ++ mutex_unlock(&sit_i->sentry_lock); ++ mutex_unlock(&curseg->curseg_mutex); ++ ++ /* writeout last modified SIT block */ ++ f2fs_put_page(page, 1); ++ ++ set_prefree_as_free_segments(sbi); ++} ++ ++static int build_sit_info(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); ++ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); ++ struct sit_info *sit_i; ++ unsigned int sit_segs, start; ++ char *src_bitmap, *dst_bitmap; ++ unsigned int bitmap_size; ++ ++ /* allocate memory for SIT information */ ++ sit_i = kzalloc(sizeof(struct sit_info), GFP_KERNEL); ++ if (!sit_i) ++ return -ENOMEM; ++ ++ SM_I(sbi)->sit_info = sit_i; ++ ++ sit_i->sentries = vzalloc(TOTAL_SEGS(sbi) * sizeof(struct seg_entry)); ++ if (!sit_i->sentries) ++ return -ENOMEM; ++ ++ bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); ++ sit_i->dirty_sentries_bitmap = kzalloc(bitmap_size, GFP_KERNEL); ++ if (!sit_i->dirty_sentries_bitmap) ++ return -ENOMEM; ++ ++ for (start = 0; start < TOTAL_SEGS(sbi); start++) { ++ sit_i->sentries[start].cur_valid_map ++ = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); ++ sit_i->sentries[start].ckpt_valid_map ++ = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); ++ if (!sit_i->sentries[start].cur_valid_map ++ || !sit_i->sentries[start].ckpt_valid_map) ++ return -ENOMEM; ++ } ++ ++ if (sbi->segs_per_sec > 1) { ++ sit_i->sec_entries = vzalloc(sbi->total_sections * ++ sizeof(struct sec_entry)); ++ if (!sit_i->sec_entries) ++ return -ENOMEM; ++ } ++ ++ /* get information related with SIT */ ++ sit_segs = le32_to_cpu(raw_super->segment_count_sit) >> 1; ++ ++ /* setup SIT bitmap from ckeckpoint pack */ ++ bitmap_size = __bitmap_size(sbi, SIT_BITMAP); ++ src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP); ++ ++ dst_bitmap = kzalloc(bitmap_size, GFP_KERNEL); ++ if (!dst_bitmap) ++ return -ENOMEM; ++ memcpy(dst_bitmap, src_bitmap, bitmap_size); ++ ++ /* init SIT information */ ++ sit_i->s_ops = &default_salloc_ops; ++ ++ sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr); ++ sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg; ++ sit_i->written_valid_blocks = le64_to_cpu(ckpt->valid_block_count); ++ sit_i->sit_bitmap = dst_bitmap; ++ sit_i->bitmap_size = bitmap_size; ++ sit_i->dirty_sentries = 0; ++ sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK; ++ sit_i->elapsed_time = le64_to_cpu(sbi->ckpt->elapsed_time); ++ sit_i->mounted_time = CURRENT_TIME_SEC.tv_sec; ++ mutex_init(&sit_i->sentry_lock); ++ return 0; ++} ++ ++static int build_free_segmap(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_sm_info *sm_info = SM_I(sbi); ++ struct free_segmap_info *free_i; ++ unsigned int bitmap_size, sec_bitmap_size; ++ ++ /* allocate memory for free segmap information */ ++ free_i = kzalloc(sizeof(struct free_segmap_info), GFP_KERNEL); ++ if (!free_i) ++ return -ENOMEM; ++ ++ SM_I(sbi)->free_info = free_i; ++ ++ bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); ++ free_i->free_segmap = kmalloc(bitmap_size, GFP_KERNEL); ++ if (!free_i->free_segmap) ++ return -ENOMEM; ++ ++ sec_bitmap_size = f2fs_bitmap_size(sbi->total_sections); ++ free_i->free_secmap = kmalloc(sec_bitmap_size, GFP_KERNEL); ++ if (!free_i->free_secmap) ++ return -ENOMEM; ++ ++ /* set all segments as dirty temporarily */ ++ memset(free_i->free_segmap, 0xff, bitmap_size); ++ memset(free_i->free_secmap, 0xff, sec_bitmap_size); ++ ++ /* init free segmap information */ ++ free_i->start_segno = ++ (unsigned int) GET_SEGNO_FROM_SEG0(sbi, sm_info->main_blkaddr); ++ free_i->free_segments = 0; ++ free_i->free_sections = 0; ++ rwlock_init(&free_i->segmap_lock); ++ return 0; ++} ++ ++static int build_curseg(struct f2fs_sb_info *sbi) ++{ ++ struct curseg_info *array = NULL; ++ int i; ++ ++ array = kzalloc(sizeof(*array) * NR_CURSEG_TYPE, GFP_KERNEL); ++ if (!array) ++ return -ENOMEM; ++ ++ SM_I(sbi)->curseg_array = array; ++ ++ for (i = 0; i < NR_CURSEG_TYPE; i++) { ++ mutex_init(&array[i].curseg_mutex); ++ array[i].sum_blk = kzalloc(PAGE_CACHE_SIZE, GFP_KERNEL); ++ if (!array[i].sum_blk) ++ return -ENOMEM; ++ array[i].segno = NULL_SEGNO; ++ array[i].next_blkoff = 0; ++ } ++ return restore_curseg_summaries(sbi); ++} ++ ++static void build_sit_entries(struct f2fs_sb_info *sbi) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); ++ struct f2fs_summary_block *sum = curseg->sum_blk; ++ unsigned int start; ++ ++ for (start = 0; start < TOTAL_SEGS(sbi); start++) { ++ struct seg_entry *se = &sit_i->sentries[start]; ++ struct f2fs_sit_block *sit_blk; ++ struct f2fs_sit_entry sit; ++ struct page *page; ++ int i; ++ ++ mutex_lock(&curseg->curseg_mutex); ++ for (i = 0; i < sits_in_cursum(sum); i++) { ++ if (le32_to_cpu(segno_in_journal(sum, i)) == start) { ++ sit = sit_in_journal(sum, i); ++ mutex_unlock(&curseg->curseg_mutex); ++ goto got_it; ++ } ++ } ++ mutex_unlock(&curseg->curseg_mutex); ++ page = get_current_sit_page(sbi, start); ++ sit_blk = (struct f2fs_sit_block *)page_address(page); ++ sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)]; ++ f2fs_put_page(page, 1); ++got_it: ++ check_block_count(sbi, start, &sit); ++ seg_info_from_raw_sit(se, &sit); ++ if (sbi->segs_per_sec > 1) { ++ struct sec_entry *e = get_sec_entry(sbi, start); ++ e->valid_blocks += se->valid_blocks; ++ } ++ } ++} ++ ++static void init_free_segmap(struct f2fs_sb_info *sbi) ++{ ++ unsigned int start; ++ int type; ++ ++ for (start = 0; start < TOTAL_SEGS(sbi); start++) { ++ struct seg_entry *sentry = get_seg_entry(sbi, start); ++ if (!sentry->valid_blocks) ++ __set_free(sbi, start); ++ } ++ ++ /* set use the current segments */ ++ for (type = CURSEG_HOT_DATA; type <= CURSEG_COLD_NODE; type++) { ++ struct curseg_info *curseg_t = CURSEG_I(sbi, type); ++ __set_test_and_inuse(sbi, curseg_t->segno); ++ } ++} ++ ++static void init_dirty_segmap(struct f2fs_sb_info *sbi) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ struct free_segmap_info *free_i = FREE_I(sbi); ++ unsigned int segno = 0, offset = 0; ++ unsigned short valid_blocks; ++ ++ while (segno < TOTAL_SEGS(sbi)) { ++ /* find dirty segment based on free segmap */ ++ segno = find_next_inuse(free_i, TOTAL_SEGS(sbi), offset); ++ if (segno >= TOTAL_SEGS(sbi)) ++ break; ++ offset = segno + 1; ++ valid_blocks = get_valid_blocks(sbi, segno, 0); ++ if (valid_blocks >= sbi->blocks_per_seg || !valid_blocks) ++ continue; ++ mutex_lock(&dirty_i->seglist_lock); ++ __locate_dirty_segment(sbi, segno, DIRTY); ++ mutex_unlock(&dirty_i->seglist_lock); ++ } ++} ++ ++static int init_victim_segmap(struct f2fs_sb_info *sbi) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); ++ ++ dirty_i->victim_segmap[FG_GC] = kzalloc(bitmap_size, GFP_KERNEL); ++ dirty_i->victim_segmap[BG_GC] = kzalloc(bitmap_size, GFP_KERNEL); ++ if (!dirty_i->victim_segmap[FG_GC] || !dirty_i->victim_segmap[BG_GC]) ++ return -ENOMEM; ++ return 0; ++} ++ ++static int build_dirty_segmap(struct f2fs_sb_info *sbi) ++{ ++ struct dirty_seglist_info *dirty_i; ++ unsigned int bitmap_size, i; ++ ++ /* allocate memory for dirty segments list information */ ++ dirty_i = kzalloc(sizeof(struct dirty_seglist_info), GFP_KERNEL); ++ if (!dirty_i) ++ return -ENOMEM; ++ ++ SM_I(sbi)->dirty_info = dirty_i; ++ mutex_init(&dirty_i->seglist_lock); ++ ++ bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); ++ ++ for (i = 0; i < NR_DIRTY_TYPE; i++) { ++ dirty_i->dirty_segmap[i] = kzalloc(bitmap_size, GFP_KERNEL); ++ dirty_i->nr_dirty[i] = 0; ++ if (!dirty_i->dirty_segmap[i]) ++ return -ENOMEM; ++ } ++ ++ init_dirty_segmap(sbi); ++ return init_victim_segmap(sbi); ++} ++ ++/** ++ * Update min, max modified time for cost-benefit GC algorithm ++ */ ++static void init_min_max_mtime(struct f2fs_sb_info *sbi) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ unsigned int segno; ++ ++ mutex_lock(&sit_i->sentry_lock); ++ ++ sit_i->min_mtime = LLONG_MAX; ++ ++ for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) { ++ unsigned int i; ++ unsigned long long mtime = 0; ++ ++ for (i = 0; i < sbi->segs_per_sec; i++) ++ mtime += get_seg_entry(sbi, segno + i)->mtime; ++ ++ mtime = div_u64(mtime, sbi->segs_per_sec); ++ ++ if (sit_i->min_mtime > mtime) ++ sit_i->min_mtime = mtime; ++ } ++ sit_i->max_mtime = get_mtime(sbi); ++ mutex_unlock(&sit_i->sentry_lock); ++} ++ ++int build_segment_manager(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); ++ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); ++ struct f2fs_sm_info *sm_info = NULL; ++ ++ sm_info = kzalloc(sizeof(struct f2fs_sm_info), GFP_KERNEL); ++ if (!sm_info) ++ return -ENOMEM; ++ ++ /* init sm info */ ++ sbi->sm_info = sm_info; ++ INIT_LIST_HEAD(&sm_info->wblist_head); ++ spin_lock_init(&sm_info->wblist_lock); ++ sm_info->seg0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr); ++ sm_info->main_blkaddr = le32_to_cpu(raw_super->main_blkaddr); ++ sm_info->segment_count = le32_to_cpu(raw_super->segment_count); ++ sm_info->rsvd_segment_count = ++ le32_to_cpu(ckpt->rsvd_segment_count); ++ sm_info->main_segment_count = ++ le32_to_cpu(raw_super->segment_count_main); ++ sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr); ++ sm_info->segment_count_ssa = ++ le32_to_cpu(raw_super->segment_count_ssa); ++ ++ if (build_sit_info(sbi)) ++ return -EINVAL; ++ if (build_free_segmap(sbi)) ++ return -EINVAL; ++ if (build_curseg(sbi)) ++ return -EINVAL; ++ ++ /* reinit free segmap based on SIT */ ++ build_sit_entries(sbi); ++ ++ init_free_segmap(sbi); ++ if (build_dirty_segmap(sbi)) ++ return -EINVAL; ++ ++ init_min_max_mtime(sbi); ++ return 0; ++} ++ ++static void discard_dirty_segmap(struct f2fs_sb_info *sbi, ++ enum dirty_type dirty_type) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ ++ mutex_lock(&dirty_i->seglist_lock); ++ kfree(dirty_i->dirty_segmap[dirty_type]); ++ dirty_i->nr_dirty[dirty_type] = 0; ++ mutex_unlock(&dirty_i->seglist_lock); ++} ++ ++void reset_victim_segmap(struct f2fs_sb_info *sbi) ++{ ++ unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); ++ memset(DIRTY_I(sbi)->victim_segmap[FG_GC], 0, bitmap_size); ++} ++ ++static void destroy_victim_segmap(struct f2fs_sb_info *sbi) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ ++ kfree(dirty_i->victim_segmap[FG_GC]); ++ kfree(dirty_i->victim_segmap[BG_GC]); ++} ++ ++static void destroy_dirty_segmap(struct f2fs_sb_info *sbi) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ int i; ++ ++ if (!dirty_i) ++ return; ++ ++ /* discard pre-free/dirty segments list */ ++ for (i = 0; i < NR_DIRTY_TYPE; i++) ++ discard_dirty_segmap(sbi, i); ++ ++ destroy_victim_segmap(sbi); ++ SM_I(sbi)->dirty_info = NULL; ++ kfree(dirty_i); ++} ++ ++static void destroy_curseg(struct f2fs_sb_info *sbi) ++{ ++ struct curseg_info *array = SM_I(sbi)->curseg_array; ++ int i; ++ ++ if (!array) ++ return; ++ SM_I(sbi)->curseg_array = NULL; ++ for (i = 0; i < NR_CURSEG_TYPE; i++) ++ kfree(array[i].sum_blk); ++ kfree(array); ++} ++ ++static void destroy_free_segmap(struct f2fs_sb_info *sbi) ++{ ++ struct free_segmap_info *free_i = SM_I(sbi)->free_info; ++ if (!free_i) ++ return; ++ SM_I(sbi)->free_info = NULL; ++ kfree(free_i->free_segmap); ++ kfree(free_i->free_secmap); ++ kfree(free_i); ++} ++ ++static void destroy_sit_info(struct f2fs_sb_info *sbi) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ unsigned int start; ++ ++ if (!sit_i) ++ return; ++ ++ if (sit_i->sentries) { ++ for (start = 0; start < TOTAL_SEGS(sbi); start++) { ++ kfree(sit_i->sentries[start].cur_valid_map); ++ kfree(sit_i->sentries[start].ckpt_valid_map); ++ } ++ } ++ vfree(sit_i->sentries); ++ vfree(sit_i->sec_entries); ++ kfree(sit_i->dirty_sentries_bitmap); ++ ++ SM_I(sbi)->sit_info = NULL; ++ kfree(sit_i->sit_bitmap); ++ kfree(sit_i); ++} ++ ++void destroy_segment_manager(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_sm_info *sm_info = SM_I(sbi); ++ destroy_dirty_segmap(sbi); ++ destroy_curseg(sbi); ++ destroy_free_segmap(sbi); ++ destroy_sit_info(sbi); ++ sbi->sm_info = NULL; ++ kfree(sm_info); ++} diff --git a/patches/linux-3.7-rc6/0105-f2fs-add-file-operations.patch b/patches/linux-3.7-rc6/0105-f2fs-add-file-operations.patch new file mode 100644 index 0000000..0416dee --- /dev/null +++ b/patches/linux-3.7-rc6/0105-f2fs-add-file-operations.patch @@ -0,0 +1,661 @@ +From 4d8f1a7a068621436faf7b1b17e6a330e0eb3a79 Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:29:21 +0000 +Subject: [PATCH] f2fs: add file operations + +This adds memory operations and file/file_inode operations. + +- F2FS supports fallocate(), mmap(), fsync(), and basic ioctl(). + +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/f2fs/file.c | 640 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 640 insertions(+) + create mode 100644 fs/f2fs/file.c + +diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c +new file mode 100644 +index 0000000..81b1fd0 +--- /dev/null ++++ b/fs/f2fs/file.c +@@ -0,0 +1,640 @@ ++/** ++ * fs/f2fs/file.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/fs.h> ++#include <linux/f2fs_fs.h> ++#include <linux/stat.h> ++#include <linux/buffer_head.h> ++#include <linux/writeback.h> ++#include <linux/falloc.h> ++#include <linux/types.h> ++#include <linux/uaccess.h> ++#include <linux/mount.h> ++ ++#include "f2fs.h" ++#include "node.h" ++#include "segment.h" ++#include "xattr.h" ++#include "acl.h" ++ ++static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, ++ struct vm_fault *vmf) ++{ ++ struct page *page = vmf->page; ++ struct inode *inode = vma->vm_file->f_path.dentry->d_inode; ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct page *node_page; ++ block_t old_blk_addr; ++ struct dnode_of_data dn; ++ int err; ++ ++ f2fs_balance_fs(sbi); ++ ++ sb_start_pagefault(inode->i_sb); ++ ++ mutex_lock_op(sbi, DATA_NEW); ++ ++ /* block allocation */ ++ set_new_dnode(&dn, inode, NULL, NULL, 0); ++ err = get_dnode_of_data(&dn, page->index, 0); ++ if (err) { ++ mutex_unlock_op(sbi, DATA_NEW); ++ goto out; ++ } ++ ++ old_blk_addr = dn.data_blkaddr; ++ node_page = dn.node_page; ++ ++ if (old_blk_addr == NULL_ADDR) { ++ err = reserve_new_block(&dn); ++ if (err) { ++ f2fs_put_dnode(&dn); ++ mutex_unlock_op(sbi, DATA_NEW); ++ goto out; ++ } ++ } ++ f2fs_put_dnode(&dn); ++ ++ mutex_unlock_op(sbi, DATA_NEW); ++ ++ lock_page(page); ++ if (page->mapping != inode->i_mapping || ++ page_offset(page) >= i_size_read(inode) || ++ !PageUptodate(page)) { ++ unlock_page(page); ++ err = -EFAULT; ++ goto out; ++ } ++ ++ /* ++ * check to see if the page is mapped already (no holes) ++ */ ++ if (PageMappedToDisk(page)) ++ goto out; ++ ++ /* fill the page */ ++ wait_on_page_writeback(page); ++ ++ /* page is wholly or partially inside EOF */ ++ if (((page->index + 1) << PAGE_CACHE_SHIFT) > i_size_read(inode)) { ++ unsigned offset; ++ offset = i_size_read(inode) & ~PAGE_CACHE_MASK; ++ zero_user_segment(page, offset, PAGE_CACHE_SIZE); ++ } ++ set_page_dirty(page); ++ SetPageUptodate(page); ++ ++ file_update_time(vma->vm_file); ++out: ++ sb_end_pagefault(inode->i_sb); ++ return block_page_mkwrite_return(err); ++} ++ ++static const struct vm_operations_struct f2fs_file_vm_ops = { ++ .fault = filemap_fault, ++ .page_mkwrite = f2fs_vm_page_mkwrite, ++}; ++ ++static int need_to_sync_dir(struct f2fs_sb_info *sbi, struct inode *inode) ++{ ++ struct dentry *dentry; ++ nid_t pino; ++ ++ inode = igrab(inode); ++ dentry = d_find_any_alias(inode); ++ if (!dentry) { ++ iput(inode); ++ return 0; ++ } ++ pino = dentry->d_parent->d_inode->i_ino; ++ dput(dentry); ++ iput(inode); ++ return !is_checkpointed_node(sbi, pino); ++} ++ ++int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) ++{ ++ struct inode *inode = file->f_mapping->host; ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ unsigned long long cur_version; ++ int ret = 0; ++ bool need_cp = false; ++ struct writeback_control wbc = { ++ .sync_mode = WB_SYNC_ALL, ++ .nr_to_write = LONG_MAX, ++ .for_reclaim = 0, ++ }; ++ ++ ret = filemap_write_and_wait_range(inode->i_mapping, start, end); ++ if (ret) ++ return ret; ++ ++ mutex_lock(&inode->i_mutex); ++ ++ if (inode->i_sb->s_flags & MS_RDONLY) ++ goto out; ++ if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) ++ goto out; ++ ++ mutex_lock(&sbi->cp_mutex); ++ cur_version = le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver); ++ mutex_unlock(&sbi->cp_mutex); ++ ++ if (F2FS_I(inode)->data_version != cur_version && ++ !(inode->i_state & I_DIRTY)) ++ goto out; ++ F2FS_I(inode)->data_version--; ++ ++ if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1) ++ need_cp = true; ++ if (is_inode_flag_set(F2FS_I(inode), FI_NEED_CP)) ++ need_cp = true; ++ if (!space_for_roll_forward(sbi)) ++ need_cp = true; ++ if (need_to_sync_dir(sbi, inode)) ++ need_cp = true; ++ ++ f2fs_write_inode(inode, NULL); ++ ++ if (need_cp) { ++ /* all the dirty node pages should be flushed for POR */ ++ ret = f2fs_sync_fs(inode->i_sb, 1); ++ clear_inode_flag(F2FS_I(inode), FI_NEED_CP); ++ } else { ++ while (sync_node_pages(sbi, inode->i_ino, &wbc) == 0) ++ f2fs_write_inode(inode, NULL); ++ filemap_fdatawait_range(sbi->node_inode->i_mapping, ++ 0, LONG_MAX); ++ } ++out: ++ mutex_unlock(&inode->i_mutex); ++ return ret; ++} ++ ++static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ file_accessed(file); ++ vma->vm_ops = &f2fs_file_vm_ops; ++ return 0; ++} ++ ++static int truncate_data_blocks_range(struct dnode_of_data *dn, int count) ++{ ++ int nr_free = 0, ofs = dn->ofs_in_node; ++ struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); ++ struct f2fs_node *raw_node; ++ __le32 *addr; ++ ++ raw_node = page_address(dn->node_page); ++ addr = blkaddr_in_node(raw_node) + ofs; ++ ++ for ( ; count > 0; count--, addr++, dn->ofs_in_node++) { ++ block_t blkaddr = le32_to_cpu(*addr); ++ if (blkaddr == NULL_ADDR) ++ continue; ++ ++ update_extent_cache(NULL_ADDR, dn); ++ invalidate_blocks(sbi, blkaddr); ++ dec_valid_block_count(sbi, dn->inode, 1); ++ nr_free++; ++ } ++ if (nr_free) { ++ set_page_dirty(dn->node_page); ++ sync_inode_page(dn); ++ } ++ dn->ofs_in_node = ofs; ++ return nr_free; ++} ++ ++void truncate_data_blocks(struct dnode_of_data *dn) ++{ ++ truncate_data_blocks_range(dn, ADDRS_PER_BLOCK); ++} ++ ++static void truncate_partial_data_page(struct inode *inode, u64 from) ++{ ++ unsigned offset = from & (PAGE_CACHE_SIZE - 1); ++ struct page *page; ++ ++ if (!offset) ++ return; ++ ++ page = find_data_page(inode, from >> PAGE_CACHE_SHIFT); ++ if (IS_ERR(page)) ++ return; ++ ++ lock_page(page); ++ wait_on_page_writeback(page); ++ zero_user(page, offset, PAGE_CACHE_SIZE - offset); ++ set_page_dirty(page); ++ f2fs_put_page(page, 1); ++} ++ ++static int truncate_blocks(struct inode *inode, u64 from) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ unsigned int blocksize = inode->i_sb->s_blocksize; ++ struct dnode_of_data dn; ++ pgoff_t free_from; ++ int count = 0; ++ int err; ++ ++ free_from = (pgoff_t) ++ ((from + blocksize - 1) >> (sbi->log_blocksize)); ++ ++ mutex_lock_op(sbi, DATA_TRUNC); ++ ++ set_new_dnode(&dn, inode, NULL, NULL, 0); ++ err = get_dnode_of_data(&dn, free_from, RDONLY_NODE); ++ if (err) { ++ if (err == -ENOENT) ++ goto free_next; ++ mutex_unlock_op(sbi, DATA_TRUNC); ++ return err; ++ } ++ ++ if (IS_INODE(dn.node_page)) ++ count = ADDRS_PER_INODE; ++ else ++ count = ADDRS_PER_BLOCK; ++ ++ count -= dn.ofs_in_node; ++ BUG_ON(count < 0); ++ if (dn.ofs_in_node || IS_INODE(dn.node_page)) { ++ truncate_data_blocks_range(&dn, count); ++ free_from += count; ++ } ++ ++ f2fs_put_dnode(&dn); ++free_next: ++ err = truncate_inode_blocks(inode, free_from); ++ mutex_unlock_op(sbi, DATA_TRUNC); ++ ++ /* lastly zero out the first data page */ ++ truncate_partial_data_page(inode, from); ++ ++ return err; ++} ++ ++void f2fs_truncate(struct inode *inode) ++{ ++ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || ++ S_ISLNK(inode->i_mode))) ++ return; ++ ++ if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) ++ return; ++ ++ if (!truncate_blocks(inode, i_size_read(inode))) { ++ inode->i_mtime = inode->i_ctime = CURRENT_TIME; ++ mark_inode_dirty(inode); ++ } ++ ++ f2fs_balance_fs(F2FS_SB(inode->i_sb)); ++} ++ ++static int f2fs_getattr(struct vfsmount *mnt, ++ struct dentry *dentry, struct kstat *stat) ++{ ++ struct inode *inode = dentry->d_inode; ++ generic_fillattr(inode, stat); ++ stat->blocks <<= 3; ++ return 0; ++} ++ ++#ifdef CONFIG_F2FS_FS_POSIX_ACL ++static void __setattr_copy(struct inode *inode, const struct iattr *attr) ++{ ++ struct f2fs_inode_info *fi = F2FS_I(inode); ++ unsigned int ia_valid = attr->ia_valid; ++ ++ if (ia_valid & ATTR_UID) ++ inode->i_uid = attr->ia_uid; ++ if (ia_valid & ATTR_GID) ++ inode->i_gid = attr->ia_gid; ++ if (ia_valid & ATTR_ATIME) ++ inode->i_atime = timespec_trunc(attr->ia_atime, ++ inode->i_sb->s_time_gran); ++ if (ia_valid & ATTR_MTIME) ++ inode->i_mtime = timespec_trunc(attr->ia_mtime, ++ inode->i_sb->s_time_gran); ++ if (ia_valid & ATTR_CTIME) ++ inode->i_ctime = timespec_trunc(attr->ia_ctime, ++ inode->i_sb->s_time_gran); ++ if (ia_valid & ATTR_MODE) { ++ umode_t mode = attr->ia_mode; ++ ++ if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) ++ mode &= ~S_ISGID; ++ set_acl_inode(fi, mode); ++ } ++} ++#else ++#define __setattr_copy setattr_copy ++#endif ++ ++int f2fs_setattr(struct dentry *dentry, struct iattr *attr) ++{ ++ struct inode *inode = dentry->d_inode; ++ struct f2fs_inode_info *fi = F2FS_I(inode); ++ int err; ++ ++ err = inode_change_ok(inode, attr); ++ if (err) ++ return err; ++ ++ if ((attr->ia_valid & ATTR_SIZE) && ++ attr->ia_size != i_size_read(inode)) { ++ truncate_setsize(inode, attr->ia_size); ++ f2fs_truncate(inode); ++ } ++ ++ __setattr_copy(inode, attr); ++ ++ if (attr->ia_valid & ATTR_MODE) { ++ err = f2fs_acl_chmod(inode); ++ if (err || is_inode_flag_set(fi, FI_ACL_MODE)) { ++ inode->i_mode = fi->i_acl_mode; ++ clear_inode_flag(fi, FI_ACL_MODE); ++ } ++ } ++ ++ mark_inode_dirty(inode); ++ return err; ++} ++ ++const struct inode_operations f2fs_file_inode_operations = { ++ .getattr = f2fs_getattr, ++ .setattr = f2fs_setattr, ++ .get_acl = f2fs_get_acl, ++#ifdef CONFIG_F2FS_FS_XATTR ++ .setxattr = generic_setxattr, ++ .getxattr = generic_getxattr, ++ .listxattr = f2fs_listxattr, ++ .removexattr = generic_removexattr, ++#endif ++}; ++ ++static void fill_zero(struct inode *inode, pgoff_t index, ++ loff_t start, loff_t len) ++{ ++ struct page *page; ++ ++ if (!len) ++ return; ++ ++ page = get_new_data_page(inode, index, false); ++ ++ if (!IS_ERR(page)) { ++ wait_on_page_writeback(page); ++ zero_user(page, start, len); ++ set_page_dirty(page); ++ f2fs_put_page(page, 1); ++ } ++} ++ ++int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end) ++{ ++ pgoff_t index; ++ int err; ++ ++ for (index = pg_start; index < pg_end; index++) { ++ struct dnode_of_data dn; ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ ++ mutex_lock_op(sbi, DATA_TRUNC); ++ set_new_dnode(&dn, inode, NULL, NULL, 0); ++ err = get_dnode_of_data(&dn, index, RDONLY_NODE); ++ if (err) { ++ mutex_unlock_op(sbi, DATA_TRUNC); ++ if (err == -ENOENT) ++ continue; ++ return err; ++ } ++ ++ if (dn.data_blkaddr != NULL_ADDR) ++ truncate_data_blocks_range(&dn, 1); ++ f2fs_put_dnode(&dn); ++ mutex_unlock_op(sbi, DATA_TRUNC); ++ } ++ return 0; ++} ++ ++static int punch_hole(struct inode *inode, loff_t offset, loff_t len, int mode) ++{ ++ pgoff_t pg_start, pg_end; ++ loff_t off_start, off_end; ++ int ret = 0; ++ ++ pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT; ++ pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT; ++ ++ off_start = offset & (PAGE_CACHE_SIZE - 1); ++ off_end = (offset + len) & (PAGE_CACHE_SIZE - 1); ++ ++ if (pg_start == pg_end) { ++ fill_zero(inode, pg_start, off_start, ++ off_end - off_start); ++ } else { ++ if (off_start) ++ fill_zero(inode, pg_start++, off_start, ++ PAGE_CACHE_SIZE - off_start); ++ if (off_end) ++ fill_zero(inode, pg_end, 0, off_end); ++ ++ if (pg_start < pg_end) { ++ struct address_space *mapping = inode->i_mapping; ++ loff_t blk_start, blk_end; ++ ++ blk_start = pg_start << PAGE_CACHE_SHIFT; ++ blk_end = pg_end << PAGE_CACHE_SHIFT; ++ truncate_inode_pages_range(mapping, blk_start, ++ blk_end - 1); ++ ret = truncate_hole(inode, pg_start, pg_end); ++ } ++ } ++ ++ if (!(mode & FALLOC_FL_KEEP_SIZE) && ++ i_size_read(inode) <= (offset + len)) { ++ i_size_write(inode, offset); ++ mark_inode_dirty(inode); ++ } ++ ++ return ret; ++} ++ ++static int expand_inode_data(struct inode *inode, loff_t offset, ++ loff_t len, int mode) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ pgoff_t index, pg_start, pg_end; ++ loff_t new_size = i_size_read(inode); ++ loff_t off_start, off_end; ++ int ret = 0; ++ ++ ret = inode_newsize_ok(inode, (len + offset)); ++ if (ret) ++ return ret; ++ ++ pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT; ++ pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT; ++ ++ off_start = offset & (PAGE_CACHE_SIZE - 1); ++ off_end = (offset + len) & (PAGE_CACHE_SIZE - 1); ++ ++ for (index = pg_start; index <= pg_end; index++) { ++ struct dnode_of_data dn; ++ ++ mutex_lock_op(sbi, DATA_NEW); ++ ++ set_new_dnode(&dn, inode, NULL, NULL, 0); ++ ret = get_dnode_of_data(&dn, index, 0); ++ if (ret) { ++ mutex_unlock_op(sbi, DATA_NEW); ++ break; ++ } ++ ++ if (dn.data_blkaddr == NULL_ADDR) { ++ ret = reserve_new_block(&dn); ++ if (ret) { ++ f2fs_put_dnode(&dn); ++ mutex_unlock_op(sbi, DATA_NEW); ++ break; ++ } ++ } ++ f2fs_put_dnode(&dn); ++ ++ mutex_unlock_op(sbi, DATA_NEW); ++ ++ if (pg_start == pg_end) ++ new_size = offset + len; ++ else if (index == pg_start && off_start) ++ new_size = (index + 1) << PAGE_CACHE_SHIFT; ++ else if (index == pg_end) ++ new_size = (index << PAGE_CACHE_SHIFT) + off_end; ++ else ++ new_size += PAGE_CACHE_SIZE; ++ } ++ ++ if (!(mode & FALLOC_FL_KEEP_SIZE) && ++ i_size_read(inode) < new_size) { ++ i_size_write(inode, new_size); ++ mark_inode_dirty(inode); ++ } ++ ++ return ret; ++} ++ ++static long f2fs_fallocate(struct file *file, int mode, ++ loff_t offset, loff_t len) ++{ ++ struct inode *inode = file->f_path.dentry->d_inode; ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ long ret; ++ ++ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) ++ return -EOPNOTSUPP; ++ ++ if (mode & FALLOC_FL_PUNCH_HOLE) ++ ret = punch_hole(inode, offset, len, mode); ++ else ++ ret = expand_inode_data(inode, offset, len, mode); ++ ++ f2fs_balance_fs(sbi); ++ return ret; ++} ++ ++#define F2FS_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL)) ++#define F2FS_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL) ++ ++static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags) ++{ ++ if (S_ISDIR(mode)) ++ return flags; ++ else if (S_ISREG(mode)) ++ return flags & F2FS_REG_FLMASK; ++ else ++ return flags & F2FS_OTHER_FLMASK; ++} ++ ++long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ struct inode *inode = filp->f_dentry->d_inode; ++ struct f2fs_inode_info *fi = F2FS_I(inode); ++ unsigned int flags; ++ int ret; ++ ++ switch (cmd) { ++ case FS_IOC_GETFLAGS: ++ flags = fi->i_flags & FS_FL_USER_VISIBLE; ++ return put_user(flags, (int __user *) arg); ++ case FS_IOC_SETFLAGS: ++ { ++ unsigned int oldflags; ++ ++ ret = mnt_want_write(filp->f_path.mnt); ++ if (ret) ++ return ret; ++ ++ if (!inode_owner_or_capable(inode)) { ++ ret = -EACCES; ++ goto out; ++ } ++ ++ if (get_user(flags, (int __user *) arg)) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ flags = f2fs_mask_flags(inode->i_mode, flags); ++ ++ mutex_lock(&inode->i_mutex); ++ ++ oldflags = fi->i_flags; ++ ++ if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { ++ if (!capable(CAP_LINUX_IMMUTABLE)) { ++ mutex_unlock(&inode->i_mutex); ++ ret = -EPERM; ++ goto out; ++ } ++ } ++ ++ flags = flags & FS_FL_USER_MODIFIABLE; ++ flags |= oldflags & ~FS_FL_USER_MODIFIABLE; ++ fi->i_flags = flags; ++ mutex_unlock(&inode->i_mutex); ++ ++ f2fs_set_inode_flags(inode); ++ inode->i_ctime = CURRENT_TIME; ++ mark_inode_dirty(inode); ++out: ++ mnt_drop_write(filp->f_path.mnt); ++ return ret; ++ } ++ default: ++ return -ENOTTY; ++ } ++} ++ ++const struct file_operations f2fs_file_operations = { ++ .llseek = generic_file_llseek, ++ .read = do_sync_read, ++ .write = do_sync_write, ++ .aio_read = generic_file_aio_read, ++ .aio_write = generic_file_aio_write, ++ .open = generic_file_open, ++ .mmap = f2fs_file_mmap, ++ .fsync = f2fs_sync_file, ++ .fallocate = f2fs_fallocate, ++ .unlocked_ioctl = f2fs_ioctl, ++ .splice_read = generic_file_splice_read, ++ .splice_write = generic_file_splice_write, ++}; diff --git a/patches/linux-3.7-rc6/0106-f2fs-add-address-space-operations-for-data.patch b/patches/linux-3.7-rc6/0106-f2fs-add-address-space-operations-for-data.patch new file mode 100644 index 0000000..998552a --- /dev/null +++ b/patches/linux-3.7-rc6/0106-f2fs-add-address-space-operations-for-data.patch @@ -0,0 +1,724 @@ +From 451af621e358f0ac96c3fe8b2dfd940fbebcda29 Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:29:49 +0000 +Subject: [PATCH] f2fs: add address space operations for data + +This adds address space operations for data. + +- F2FS supports readpages(), writepages(), and direct_IO(). + +- Because of out-of-place writes, f2fs_direct_IO() does not write data in place. + +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/f2fs/data.c | 701 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 701 insertions(+) + create mode 100644 fs/f2fs/data.c + +diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c +new file mode 100644 +index 0000000..c2fd0a8 +--- /dev/null ++++ b/fs/f2fs/data.c +@@ -0,0 +1,701 @@ ++/** ++ * fs/f2fs/data.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/fs.h> ++#include <linux/f2fs_fs.h> ++#include <linux/buffer_head.h> ++#include <linux/mpage.h> ++#include <linux/writeback.h> ++#include <linux/backing-dev.h> ++#include <linux/blkdev.h> ++#include <linux/bio.h> ++ ++#include "f2fs.h" ++#include "node.h" ++#include "segment.h" ++ ++/** ++ * Lock ordering for the change of data block address: ++ * ->data_page ++ * ->node_page ++ * update block addresses in the node page ++ */ ++static void __set_data_blkaddr(struct dnode_of_data *dn, block_t new_addr) ++{ ++ struct f2fs_node *rn; ++ __le32 *addr_array; ++ struct page *node_page = dn->node_page; ++ unsigned int ofs_in_node = dn->ofs_in_node; ++ ++ wait_on_page_writeback(node_page); ++ ++ rn = (struct f2fs_node *)page_address(node_page); ++ ++ /* Get physical address of data block */ ++ addr_array = blkaddr_in_node(rn); ++ addr_array[ofs_in_node] = cpu_to_le32(new_addr); ++ set_page_dirty(node_page); ++} ++ ++int reserve_new_block(struct dnode_of_data *dn) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); ++ ++ if (is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC)) ++ return -EPERM; ++ if (!inc_valid_block_count(sbi, dn->inode, 1)) ++ return -ENOSPC; ++ ++ __set_data_blkaddr(dn, NEW_ADDR); ++ dn->data_blkaddr = NEW_ADDR; ++ sync_inode_page(dn); ++ return 0; ++} ++ ++static int check_extent_cache(struct inode *inode, pgoff_t pgofs, ++ struct buffer_head *bh_result) ++{ ++ struct f2fs_inode_info *fi = F2FS_I(inode); ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ pgoff_t start_fofs, end_fofs; ++ block_t start_blkaddr; ++ ++ read_lock(&fi->ext.ext_lock); ++ if (fi->ext.len == 0) { ++ read_unlock(&fi->ext.ext_lock); ++ return 0; ++ } ++ ++ sbi->total_hit_ext++; ++ start_fofs = fi->ext.fofs; ++ end_fofs = fi->ext.fofs + fi->ext.len - 1; ++ start_blkaddr = fi->ext.blk_addr; ++ ++ if (pgofs >= start_fofs && pgofs <= end_fofs) { ++ unsigned int blkbits = inode->i_sb->s_blocksize_bits; ++ size_t count; ++ ++ clear_buffer_new(bh_result); ++ map_bh(bh_result, inode->i_sb, ++ start_blkaddr + pgofs - start_fofs); ++ count = end_fofs - pgofs + 1; ++ if (count < (UINT_MAX >> blkbits)) ++ bh_result->b_size = (count << blkbits); ++ else ++ bh_result->b_size = UINT_MAX; ++ ++ sbi->read_hit_ext++; ++ read_unlock(&fi->ext.ext_lock); ++ return 1; ++ } ++ read_unlock(&fi->ext.ext_lock); ++ return 0; ++} ++ ++void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn) ++{ ++ struct f2fs_inode_info *fi = F2FS_I(dn->inode); ++ pgoff_t fofs, start_fofs, end_fofs; ++ block_t start_blkaddr, end_blkaddr; ++ ++ BUG_ON(blk_addr == NEW_ADDR); ++ fofs = start_bidx_of_node(ofs_of_node(dn->node_page)) + dn->ofs_in_node; ++ ++ /* Update the page address in the parent node */ ++ __set_data_blkaddr(dn, blk_addr); ++ ++ write_lock(&fi->ext.ext_lock); ++ ++ start_fofs = fi->ext.fofs; ++ end_fofs = fi->ext.fofs + fi->ext.len - 1; ++ start_blkaddr = fi->ext.blk_addr; ++ end_blkaddr = fi->ext.blk_addr + fi->ext.len - 1; ++ ++ /* Drop and initialize the matched extent */ ++ if (fi->ext.len == 1 && fofs == start_fofs) ++ fi->ext.len = 0; ++ ++ /* Initial extent */ ++ if (fi->ext.len == 0) { ++ if (blk_addr != NULL_ADDR) { ++ fi->ext.fofs = fofs; ++ fi->ext.blk_addr = blk_addr; ++ fi->ext.len = 1; ++ } ++ goto end_update; ++ } ++ ++ /* Frone merge */ ++ if (fofs == start_fofs - 1 && blk_addr == start_blkaddr - 1) { ++ fi->ext.fofs--; ++ fi->ext.blk_addr--; ++ fi->ext.len++; ++ goto end_update; ++ } ++ ++ /* Back merge */ ++ if (fofs == end_fofs + 1 && blk_addr == end_blkaddr + 1) { ++ fi->ext.len++; ++ goto end_update; ++ } ++ ++ /* Split the existing extent */ ++ if (fi->ext.len > 1 && ++ fofs >= start_fofs && fofs <= end_fofs) { ++ if ((end_fofs - fofs) < (fi->ext.len >> 1)) { ++ fi->ext.len = fofs - start_fofs; ++ } else { ++ fi->ext.fofs = fofs + 1; ++ fi->ext.blk_addr = start_blkaddr + ++ fofs - start_fofs + 1; ++ fi->ext.len -= fofs - start_fofs + 1; ++ } ++ goto end_update; ++ } ++ write_unlock(&fi->ext.ext_lock); ++ return; ++ ++end_update: ++ write_unlock(&fi->ext.ext_lock); ++ sync_inode_page(dn); ++ return; ++} ++ ++struct page *find_data_page(struct inode *inode, pgoff_t index) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct address_space *mapping = inode->i_mapping; ++ struct dnode_of_data dn; ++ struct page *page; ++ int err; ++ ++ page = find_get_page(mapping, index); ++ if (page && PageUptodate(page)) ++ return page; ++ f2fs_put_page(page, 0); ++ ++ set_new_dnode(&dn, inode, NULL, NULL, 0); ++ err = get_dnode_of_data(&dn, index, RDONLY_NODE); ++ if (err) ++ return ERR_PTR(err); ++ f2fs_put_dnode(&dn); ++ ++ if (dn.data_blkaddr == NULL_ADDR) ++ return ERR_PTR(-ENOENT); ++ ++ /* By fallocate(), there is no cached page, but with NEW_ADDR */ ++ if (dn.data_blkaddr == NEW_ADDR) ++ return ERR_PTR(-EINVAL); ++ ++ page = grab_cache_page(mapping, index); ++ if (!page) ++ return ERR_PTR(-ENOMEM); ++ ++ err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC); ++ if (err) { ++ f2fs_put_page(page, 1); ++ return ERR_PTR(err); ++ } ++ unlock_page(page); ++ return page; ++} ++ ++/** ++ * If it tries to access a hole, return an error. ++ * Because, the callers, functions in dir.c and GC, should be able to know ++ * whether this page exists or not. ++ */ ++struct page *get_lock_data_page(struct inode *inode, pgoff_t index) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct address_space *mapping = inode->i_mapping; ++ struct dnode_of_data dn; ++ struct page *page; ++ int err; ++ ++ set_new_dnode(&dn, inode, NULL, NULL, 0); ++ err = get_dnode_of_data(&dn, index, RDONLY_NODE); ++ if (err) ++ return ERR_PTR(err); ++ f2fs_put_dnode(&dn); ++ ++ if (dn.data_blkaddr == NULL_ADDR) ++ return ERR_PTR(-ENOENT); ++ ++ page = grab_cache_page(mapping, index); ++ if (!page) ++ return ERR_PTR(-ENOMEM); ++ ++ if (PageUptodate(page)) ++ return page; ++ ++ BUG_ON(dn.data_blkaddr == NEW_ADDR); ++ BUG_ON(dn.data_blkaddr == NULL_ADDR); ++ ++ err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC); ++ if (err) { ++ f2fs_put_page(page, 1); ++ return ERR_PTR(err); ++ } ++ return page; ++} ++ ++/** ++ * Caller ensures that this data page is never allocated. ++ * A new zero-filled data page is allocated in the page cache. ++ */ ++struct page *get_new_data_page(struct inode *inode, pgoff_t index, ++ bool new_i_size) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct address_space *mapping = inode->i_mapping; ++ struct page *page; ++ struct dnode_of_data dn; ++ int err; ++ ++ set_new_dnode(&dn, inode, NULL, NULL, 0); ++ err = get_dnode_of_data(&dn, index, 0); ++ if (err) ++ return ERR_PTR(err); ++ ++ if (dn.data_blkaddr == NULL_ADDR) { ++ if (reserve_new_block(&dn)) { ++ f2fs_put_dnode(&dn); ++ return ERR_PTR(-ENOSPC); ++ } ++ } ++ f2fs_put_dnode(&dn); ++ ++ page = grab_cache_page(mapping, index); ++ if (!page) ++ return ERR_PTR(-ENOMEM); ++ ++ if (PageUptodate(page)) ++ return page; ++ ++ if (dn.data_blkaddr == NEW_ADDR) { ++ zero_user_segment(page, 0, PAGE_CACHE_SIZE); ++ } else { ++ err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC); ++ if (err) { ++ f2fs_put_page(page, 1); ++ return ERR_PTR(err); ++ } ++ } ++ SetPageUptodate(page); ++ ++ if (new_i_size && ++ i_size_read(inode) < ((index + 1) << PAGE_CACHE_SHIFT)) { ++ i_size_write(inode, ((index + 1) << PAGE_CACHE_SHIFT)); ++ mark_inode_dirty_sync(inode); ++ } ++ return page; ++} ++ ++static void read_end_io(struct bio *bio, int err) ++{ ++ const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); ++ struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; ++ ++ do { ++ struct page *page = bvec->bv_page; ++ ++ if (--bvec >= bio->bi_io_vec) ++ prefetchw(&bvec->bv_page->flags); ++ ++ if (uptodate) { ++ SetPageUptodate(page); ++ } else { ++ ClearPageUptodate(page); ++ SetPageError(page); ++ } ++ unlock_page(page); ++ } while (bvec >= bio->bi_io_vec); ++ kfree(bio->bi_private); ++ bio_put(bio); ++} ++ ++/** ++ * Fill the locked page with data located in the block address. ++ * Read operation is synchronous, and caller must unlock the page. ++ */ ++int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page, ++ block_t blk_addr, int type) ++{ ++ struct block_device *bdev = sbi->sb->s_bdev; ++ bool sync = (type == READ_SYNC); ++ struct bio *bio; ++ ++ /* This page can be already read by other threads */ ++ if (PageUptodate(page)) { ++ if (!sync) ++ unlock_page(page); ++ return 0; ++ } ++ ++ down_read(&sbi->bio_sem); ++ ++ /* Allocate a new bio */ ++ bio = f2fs_bio_alloc(bdev, blk_addr << (sbi->log_blocksize - 9), ++ 1, GFP_NOFS | __GFP_HIGH); ++ ++ /* Initialize the bio */ ++ bio->bi_end_io = read_end_io; ++ if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) { ++ kfree(bio->bi_private); ++ bio_put(bio); ++ up_read(&sbi->bio_sem); ++ return -EFAULT; ++ } ++ ++ submit_bio(type, bio); ++ up_read(&sbi->bio_sem); ++ ++ /* wait for read completion if sync */ ++ if (sync) { ++ lock_page(page); ++ if (PageError(page)) ++ return -EIO; ++ } ++ return 0; ++} ++ ++/** ++ * This function should be used by the data read flow only where it ++ * does not check the "create" flag that indicates block allocation. ++ * The reason for this special functionality is to exploit VFS readahead ++ * mechanism. ++ */ ++static int get_data_block_ro(struct inode *inode, sector_t iblock, ++ struct buffer_head *bh_result, int create) ++{ ++ unsigned int blkbits = inode->i_sb->s_blocksize_bits; ++ unsigned maxblocks = bh_result->b_size >> blkbits; ++ struct dnode_of_data dn; ++ pgoff_t pgofs; ++ int err; ++ ++ /* Get the page offset from the block offset(iblock) */ ++ pgofs = (pgoff_t)(iblock >> (PAGE_CACHE_SHIFT - blkbits)); ++ ++ if (check_extent_cache(inode, pgofs, bh_result)) ++ return 0; ++ ++ /* When reading holes, we need its node page */ ++ set_new_dnode(&dn, inode, NULL, NULL, 0); ++ err = get_dnode_of_data(&dn, pgofs, RDONLY_NODE); ++ if (err) ++ return (err == -ENOENT) ? 0 : err; ++ ++ /* It does not support data allocation */ ++ BUG_ON(create); ++ ++ if (dn.data_blkaddr != NEW_ADDR && dn.data_blkaddr != NULL_ADDR) { ++ int i; ++ unsigned int end_offset; ++ ++ end_offset = IS_INODE(dn.node_page) ? ++ ADDRS_PER_INODE : ++ ADDRS_PER_BLOCK; ++ ++ clear_buffer_new(bh_result); ++ ++ /* Give more consecutive addresses for the read ahead */ ++ for (i = 0; i < end_offset - dn.ofs_in_node; i++) ++ if (((datablock_addr(dn.node_page, ++ dn.ofs_in_node + i)) ++ != (dn.data_blkaddr + i)) || maxblocks == i) ++ break; ++ map_bh(bh_result, inode->i_sb, dn.data_blkaddr); ++ bh_result->b_size = (i << blkbits); ++ } ++ f2fs_put_dnode(&dn); ++ return 0; ++} ++ ++static int f2fs_read_data_page(struct file *file, struct page *page) ++{ ++ return mpage_readpage(page, get_data_block_ro); ++} ++ ++static int f2fs_read_data_pages(struct file *file, ++ struct address_space *mapping, ++ struct list_head *pages, unsigned nr_pages) ++{ ++ return mpage_readpages(mapping, pages, nr_pages, get_data_block_ro); ++} ++ ++int do_write_data_page(struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ block_t old_blk_addr, new_blk_addr; ++ struct dnode_of_data dn; ++ int err = 0; ++ ++ set_new_dnode(&dn, inode, NULL, NULL, 0); ++ err = get_dnode_of_data(&dn, page->index, RDONLY_NODE); ++ if (err) ++ return err; ++ ++ old_blk_addr = dn.data_blkaddr; ++ ++ /* This page is already truncated */ ++ if (old_blk_addr == NULL_ADDR) ++ goto out_writepage; ++ ++ set_page_writeback(page); ++ ++ /* ++ * If current allocation needs SSR, ++ * it had better in-place writes for updated data. ++ */ ++ if (old_blk_addr != NEW_ADDR && !is_cold_data(page) && ++ need_inplace_update(inode)) { ++ rewrite_data_page(F2FS_SB(inode->i_sb), page, ++ old_blk_addr); ++ } else { ++ write_data_page(inode, page, &dn, ++ old_blk_addr, &new_blk_addr); ++ update_extent_cache(new_blk_addr, &dn); ++ F2FS_I(inode)->data_version = ++ le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver); ++ } ++out_writepage: ++ f2fs_put_dnode(&dn); ++ return err; ++} ++ ++static int f2fs_write_data_page(struct page *page, ++ struct writeback_control *wbc) ++{ ++ struct inode *inode = page->mapping->host; ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ loff_t i_size = i_size_read(inode); ++ const pgoff_t end_index = ((unsigned long long) i_size) ++ >> PAGE_CACHE_SHIFT; ++ unsigned offset; ++ int err = 0; ++ ++ if (page->index < end_index) ++ goto out; ++ ++ /* ++ * If the offset is out-of-range of file size, ++ * this page does not have to be written to disk. ++ */ ++ offset = i_size & (PAGE_CACHE_SIZE - 1); ++ if ((page->index >= end_index + 1) || !offset) { ++ if (S_ISDIR(inode->i_mode)) { ++ dec_page_count(sbi, F2FS_DIRTY_DENTS); ++ inode_dec_dirty_dents(inode); ++ } ++ goto unlock_out; ++ } ++ ++ zero_user_segment(page, offset, PAGE_CACHE_SIZE); ++out: ++ if (sbi->por_doing) ++ goto redirty_out; ++ ++ if (wbc->for_reclaim && !S_ISDIR(inode->i_mode) && !is_cold_data(page)) ++ goto redirty_out; ++ ++ mutex_lock_op(sbi, DATA_WRITE); ++ if (S_ISDIR(inode->i_mode)) { ++ dec_page_count(sbi, F2FS_DIRTY_DENTS); ++ inode_dec_dirty_dents(inode); ++ } ++ err = do_write_data_page(page); ++ if (err && err != -ENOENT) { ++ wbc->pages_skipped++; ++ set_page_dirty(page); ++ } ++ mutex_unlock_op(sbi, DATA_WRITE); ++ ++ if (wbc->for_reclaim) ++ f2fs_submit_bio(sbi, DATA, true); ++ ++ if (err == -ENOENT) ++ goto unlock_out; ++ ++ clear_cold_data(page); ++ unlock_page(page); ++ ++ if (!wbc->for_reclaim && !S_ISDIR(inode->i_mode)) ++ f2fs_balance_fs(sbi); ++ return 0; ++ ++unlock_out: ++ unlock_page(page); ++ return (err == -ENOENT) ? 0 : err; ++ ++redirty_out: ++ wbc->pages_skipped++; ++ set_page_dirty(page); ++ return AOP_WRITEPAGE_ACTIVATE; ++} ++ ++#define MAX_DESIRED_PAGES_WP 4096 ++ ++int f2fs_write_data_pages(struct address_space *mapping, ++ struct writeback_control *wbc) ++{ ++ struct inode *inode = mapping->host; ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ int ret; ++ long excess_nrtw = 0, desired_nrtw; ++ ++ if (wbc->nr_to_write < MAX_DESIRED_PAGES_WP) { ++ desired_nrtw = MAX_DESIRED_PAGES_WP; ++ excess_nrtw = desired_nrtw - wbc->nr_to_write; ++ wbc->nr_to_write = desired_nrtw; ++ } ++ ++ if (!S_ISDIR(inode->i_mode)) ++ mutex_lock(&sbi->writepages); ++ ret = generic_writepages(mapping, wbc); ++ if (!S_ISDIR(inode->i_mode)) ++ mutex_unlock(&sbi->writepages); ++ f2fs_submit_bio(sbi, DATA, (wbc->sync_mode == WB_SYNC_ALL)); ++ ++ remove_dirty_dir_inode(inode); ++ ++ wbc->nr_to_write -= excess_nrtw; ++ return ret; ++} ++ ++static int f2fs_write_begin(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata) ++{ ++ struct inode *inode = mapping->host; ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct page *page; ++ pgoff_t index = ((unsigned long long) pos) >> PAGE_CACHE_SHIFT; ++ struct dnode_of_data dn; ++ int err = 0; ++ ++ /* for nobh_write_end */ ++ *fsdata = NULL; ++ ++ f2fs_balance_fs(sbi); ++ ++ page = grab_cache_page_write_begin(mapping, index, flags); ++ if (!page) ++ return -ENOMEM; ++ *pagep = page; ++ ++ mutex_lock_op(sbi, DATA_NEW); ++ ++ set_new_dnode(&dn, inode, NULL, NULL, 0); ++ err = get_dnode_of_data(&dn, index, 0); ++ if (err) { ++ mutex_unlock_op(sbi, DATA_NEW); ++ f2fs_put_page(page, 1); ++ return err; ++ } ++ ++ if (dn.data_blkaddr == NULL_ADDR) { ++ err = reserve_new_block(&dn); ++ if (err) { ++ f2fs_put_dnode(&dn); ++ mutex_unlock_op(sbi, DATA_NEW); ++ f2fs_put_page(page, 1); ++ return err; ++ } ++ } ++ f2fs_put_dnode(&dn); ++ ++ mutex_unlock_op(sbi, DATA_NEW); ++ ++ if ((len == PAGE_CACHE_SIZE) || PageUptodate(page)) ++ return 0; ++ ++ if ((pos & PAGE_CACHE_MASK) >= i_size_read(inode)) { ++ unsigned start = pos & (PAGE_CACHE_SIZE - 1); ++ unsigned end = start + len; ++ ++ /* Reading beyond i_size is simple: memset to zero */ ++ zero_user_segments(page, 0, start, end, PAGE_CACHE_SIZE); ++ return 0; ++ } ++ ++ if (dn.data_blkaddr == NEW_ADDR) { ++ zero_user_segment(page, 0, PAGE_CACHE_SIZE); ++ } else { ++ err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC); ++ if (err) { ++ f2fs_put_page(page, 1); ++ return err; ++ } ++ } ++ SetPageUptodate(page); ++ clear_cold_data(page); ++ return 0; ++} ++ ++static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, ++ const struct iovec *iov, loff_t offset, unsigned long nr_segs) ++{ ++ struct file *file = iocb->ki_filp; ++ struct inode *inode = file->f_mapping->host; ++ ++ if (rw == WRITE) ++ return 0; ++ ++ /* Needs synchronization with the cleaner */ ++ return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, ++ get_data_block_ro); ++} ++ ++static void f2fs_invalidate_data_page(struct page *page, unsigned long offset) ++{ ++ struct inode *inode = page->mapping->host; ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ if (S_ISDIR(inode->i_mode) && PageDirty(page)) { ++ dec_page_count(sbi, F2FS_DIRTY_DENTS); ++ inode_dec_dirty_dents(inode); ++ } ++ ClearPagePrivate(page); ++} ++ ++static int f2fs_release_data_page(struct page *page, gfp_t wait) ++{ ++ ClearPagePrivate(page); ++ return 0; ++} ++ ++static int f2fs_set_data_page_dirty(struct page *page) ++{ ++ struct address_space *mapping = page->mapping; ++ struct inode *inode = mapping->host; ++ ++ SetPageUptodate(page); ++ if (!PageDirty(page)) { ++ __set_page_dirty_nobuffers(page); ++ set_dirty_dir_page(inode, page); ++ return 1; ++ } ++ return 0; ++} ++ ++const struct address_space_operations f2fs_dblock_aops = { ++ .readpage = f2fs_read_data_page, ++ .readpages = f2fs_read_data_pages, ++ .writepage = f2fs_write_data_page, ++ .writepages = f2fs_write_data_pages, ++ .write_begin = f2fs_write_begin, ++ .write_end = nobh_write_end, ++ .set_page_dirty = f2fs_set_data_page_dirty, ++ .invalidatepage = f2fs_invalidate_data_page, ++ .releasepage = f2fs_release_data_page, ++ .direct_IO = f2fs_direct_IO, ++}; diff --git a/patches/linux-3.7-rc6/0107-f2fs-add-core-inode-operations.patch b/patches/linux-3.7-rc6/0107-f2fs-add-core-inode-operations.patch new file mode 100644 index 0000000..60484b6 --- /dev/null +++ b/patches/linux-3.7-rc6/0107-f2fs-add-core-inode-operations.patch @@ -0,0 +1,282 @@ +From dcf1bc84b5065c486a3eb6d516b3f7d150138120 Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:30:16 +0000 +Subject: [PATCH] f2fs: add core inode operations + +This adds core functions to get, read, write, and evict an inode. + +Signed-off-by: Changman Lee <cm224.lee@samsung.com> +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/f2fs/inode.c | 262 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 262 insertions(+) + create mode 100644 fs/f2fs/inode.c + +diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c +new file mode 100644 +index 0000000..0cf61da +--- /dev/null ++++ b/fs/f2fs/inode.c +@@ -0,0 +1,262 @@ ++/** ++ * fs/f2fs/inode.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/fs.h> ++#include <linux/f2fs_fs.h> ++#include <linux/buffer_head.h> ++#include <linux/writeback.h> ++ ++#include "f2fs.h" ++#include "node.h" ++ ++struct f2fs_iget_args { ++ u64 ino; ++ int on_free; ++}; ++ ++void f2fs_set_inode_flags(struct inode *inode) ++{ ++ unsigned int flags = F2FS_I(inode)->i_flags; ++ ++ inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | ++ S_NOATIME | S_DIRSYNC); ++ ++ if (flags & FS_SYNC_FL) ++ inode->i_flags |= S_SYNC; ++ if (flags & FS_APPEND_FL) ++ inode->i_flags |= S_APPEND; ++ if (flags & FS_IMMUTABLE_FL) ++ inode->i_flags |= S_IMMUTABLE; ++ if (flags & FS_NOATIME_FL) ++ inode->i_flags |= S_NOATIME; ++ if (flags & FS_DIRSYNC_FL) ++ inode->i_flags |= S_DIRSYNC; ++} ++ ++static int f2fs_iget_test(struct inode *inode, void *data) ++{ ++ struct f2fs_iget_args *args = data; ++ ++ if (inode->i_ino != args->ino) ++ return 0; ++ if (inode->i_state & (I_FREEING | I_WILL_FREE)) { ++ args->on_free = 1; ++ return 0; ++ } ++ return 1; ++} ++ ++struct inode *f2fs_iget_nowait(struct super_block *sb, unsigned long ino) ++{ ++ struct f2fs_iget_args args = { ++ .ino = ino, ++ .on_free = 0 ++ }; ++ struct inode *inode = ilookup5(sb, ino, f2fs_iget_test, &args); ++ ++ if (inode) ++ return inode; ++ if (!args.on_free) ++ return f2fs_iget(sb, ino); ++ return ERR_PTR(-ENOENT); ++} ++ ++static int do_read_inode(struct inode *inode) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct f2fs_inode_info *fi = F2FS_I(inode); ++ struct page *node_page; ++ struct f2fs_node *rn; ++ struct f2fs_inode *ri; ++ ++ /* Check if ino is within scope */ ++ check_nid_range(sbi, inode->i_ino); ++ ++ node_page = get_node_page(sbi, inode->i_ino); ++ if (IS_ERR(node_page)) ++ return PTR_ERR(node_page); ++ ++ rn = page_address(node_page); ++ ri = &(rn->i); ++ ++ inode->i_mode = le16_to_cpu(ri->i_mode); ++ i_uid_write(inode, le32_to_cpu(ri->i_uid)); ++ i_gid_write(inode, le32_to_cpu(ri->i_gid)); ++ set_nlink(inode, le32_to_cpu(ri->i_links)); ++ inode->i_size = le64_to_cpu(ri->i_size); ++ inode->i_blocks = le64_to_cpu(ri->i_blocks); ++ ++ inode->i_atime.tv_sec = le64_to_cpu(ri->i_mtime); ++ inode->i_ctime.tv_sec = le64_to_cpu(ri->i_ctime); ++ inode->i_mtime.tv_sec = le64_to_cpu(ri->i_mtime); ++ inode->i_atime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec); ++ inode->i_ctime.tv_nsec = le32_to_cpu(ri->i_ctime_nsec); ++ inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec); ++ ++ fi->current_depth = le32_to_cpu(ri->current_depth); ++ fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid); ++ fi->i_flags = le32_to_cpu(ri->i_flags); ++ fi->flags = 0; ++ fi->data_version = le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver) - 1; ++ fi->i_advise = ri->i_advise; ++ get_extent_info(&fi->ext, ri->i_ext); ++ f2fs_put_page(node_page, 1); ++ return 0; ++} ++ ++struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(sb); ++ struct inode *inode; ++ int ret; ++ ++ inode = iget_locked(sb, ino); ++ if (!inode) ++ return ERR_PTR(-ENOMEM); ++ if (!(inode->i_state & I_NEW)) ++ return inode; ++ if (ino == F2FS_NODE_INO(sbi) || ino == F2FS_META_INO(sbi)) ++ goto make_now; ++ ++ ret = do_read_inode(inode); ++ if (ret) ++ goto bad_inode; ++ ++ if (!sbi->por_doing && inode->i_nlink == 0) { ++ ret = -ENOENT; ++ goto bad_inode; ++ } ++ ++make_now: ++ if (ino == F2FS_NODE_INO(sbi)) { ++ inode->i_mapping->a_ops = &f2fs_node_aops; ++ mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_MOVABLE); ++ } else if (ino == F2FS_META_INO(sbi)) { ++ inode->i_mapping->a_ops = &f2fs_meta_aops; ++ mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_MOVABLE); ++ } else if (S_ISREG(inode->i_mode)) { ++ inode->i_op = &f2fs_file_inode_operations; ++ inode->i_fop = &f2fs_file_operations; ++ inode->i_mapping->a_ops = &f2fs_dblock_aops; ++ } else if (S_ISDIR(inode->i_mode)) { ++ inode->i_op = &f2fs_dir_inode_operations; ++ inode->i_fop = &f2fs_dir_operations; ++ inode->i_mapping->a_ops = &f2fs_dblock_aops; ++ mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER_MOVABLE | ++ __GFP_ZERO); ++ } else if (S_ISLNK(inode->i_mode)) { ++ inode->i_op = &f2fs_symlink_inode_operations; ++ inode->i_mapping->a_ops = &f2fs_dblock_aops; ++ } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || ++ S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { ++ inode->i_op = &f2fs_special_inode_operations; ++ init_special_inode(inode, inode->i_mode, inode->i_rdev); ++ } else { ++ ret = -EIO; ++ goto bad_inode; ++ } ++ unlock_new_inode(inode); ++ ++ return inode; ++ ++bad_inode: ++ iget_failed(inode); ++ return ERR_PTR(ret); ++} ++ ++void update_inode(struct inode *inode, struct page *node_page) ++{ ++ struct f2fs_node *rn; ++ struct f2fs_inode *ri; ++ ++ wait_on_page_writeback(node_page); ++ ++ rn = page_address(node_page); ++ ri = &(rn->i); ++ ++ ri->i_mode = cpu_to_le16(inode->i_mode); ++ ri->i_advise = F2FS_I(inode)->i_advise; ++ ri->i_uid = cpu_to_le32(i_uid_read(inode)); ++ ri->i_gid = cpu_to_le32(i_gid_read(inode)); ++ ri->i_links = cpu_to_le32(inode->i_nlink); ++ ri->i_size = cpu_to_le64(i_size_read(inode)); ++ ri->i_blocks = cpu_to_le64(inode->i_blocks); ++ set_raw_extent(&F2FS_I(inode)->ext, &ri->i_ext); ++ ++ ri->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec); ++ ri->i_mtime = cpu_to_le64(inode->i_mtime.tv_sec); ++ ri->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); ++ ri->i_mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec); ++ ri->current_depth = cpu_to_le32(F2FS_I(inode)->current_depth); ++ ri->i_xattr_nid = cpu_to_le32(F2FS_I(inode)->i_xattr_nid); ++ ri->i_flags = cpu_to_le32(F2FS_I(inode)->i_flags); ++ set_page_dirty(node_page); ++} ++ ++int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct page *node_page; ++ bool need_lock = false; ++ ++ if (inode->i_ino == F2FS_NODE_INO(sbi) || ++ inode->i_ino == F2FS_META_INO(sbi)) ++ return 0; ++ ++ node_page = get_node_page(sbi, inode->i_ino); ++ if (IS_ERR(node_page)) ++ return PTR_ERR(node_page); ++ ++ if (!PageDirty(node_page)) { ++ need_lock = true; ++ f2fs_put_page(node_page, 1); ++ mutex_lock(&sbi->write_inode); ++ node_page = get_node_page(sbi, inode->i_ino); ++ if (IS_ERR(node_page)) { ++ mutex_unlock(&sbi->write_inode); ++ return PTR_ERR(node_page); ++ } ++ } ++ update_inode(inode, node_page); ++ f2fs_put_page(node_page, 1); ++ if (need_lock) ++ mutex_unlock(&sbi->write_inode); ++ return 0; ++} ++ ++/** ++ * Called at the last iput() if i_nlink is zero ++ */ ++void f2fs_evict_inode(struct inode *inode) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ ++ truncate_inode_pages(&inode->i_data, 0); ++ ++ if (inode->i_ino == F2FS_NODE_INO(sbi) || ++ inode->i_ino == F2FS_META_INO(sbi)) ++ goto no_delete; ++ ++ BUG_ON(atomic_read(&F2FS_I(inode)->dirty_dents)); ++ remove_dirty_dir_inode(inode); ++ ++ if (inode->i_nlink || is_bad_inode(inode)) ++ goto no_delete; ++ ++ set_inode_flag(F2FS_I(inode), FI_NO_ALLOC); ++ i_size_write(inode, 0); ++ ++ if (F2FS_HAS_BLOCKS(inode)) ++ f2fs_truncate(inode); ++ ++ remove_inode_page(inode); ++no_delete: ++ clear_inode(inode); ++} diff --git a/patches/linux-3.7-rc6/0108-f2fs-add-inode-operations-for-special-inodes.patch b/patches/linux-3.7-rc6/0108-f2fs-add-inode-operations-for-special-inodes.patch new file mode 100644 index 0000000..4992a4e --- /dev/null +++ b/patches/linux-3.7-rc6/0108-f2fs-add-inode-operations-for-special-inodes.patch @@ -0,0 +1,514 @@ +From 9a81dfce3a0c412925ec2fb68becab30e774089e Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:30:45 +0000 +Subject: [PATCH] f2fs: add inode operations for special inodes + +This adds inode operations for directory, symlink, and special inodes. + +Signed-off-by: Changman Lee <cm224.lee@samsung.com> +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/f2fs/namei.c | 494 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 494 insertions(+) + create mode 100644 fs/f2fs/namei.c + +diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c +new file mode 100644 +index 0000000..899d144 +--- /dev/null ++++ b/fs/f2fs/namei.c +@@ -0,0 +1,494 @@ ++/** ++ * fs/f2fs/namei.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/fs.h> ++#include <linux/f2fs_fs.h> ++#include <linux/pagemap.h> ++#include <linux/sched.h> ++#include <linux/ctype.h> ++ ++#include "f2fs.h" ++#include "xattr.h" ++#include "acl.h" ++ ++static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) ++{ ++ struct super_block *sb = dir->i_sb; ++ struct f2fs_sb_info *sbi = F2FS_SB(sb); ++ nid_t ino; ++ struct inode *inode; ++ bool nid_free = false; ++ int err; ++ ++ inode = new_inode(sb); ++ if (!inode) ++ return ERR_PTR(-ENOMEM); ++ ++ mutex_lock_op(sbi, NODE_NEW); ++ if (!alloc_nid(sbi, &ino)) { ++ mutex_unlock_op(sbi, NODE_NEW); ++ err = -ENOSPC; ++ goto fail; ++ } ++ mutex_unlock_op(sbi, NODE_NEW); ++ ++ inode->i_uid = current_fsuid(); ++ ++ if (dir->i_mode & S_ISGID) { ++ inode->i_gid = dir->i_gid; ++ if (S_ISDIR(mode)) ++ mode |= S_ISGID; ++ } else { ++ inode->i_gid = current_fsgid(); ++ } ++ ++ inode->i_ino = ino; ++ inode->i_mode = mode; ++ inode->i_blocks = 0; ++ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; ++ ++ err = insert_inode_locked(inode); ++ if (err) { ++ err = -EINVAL; ++ nid_free = true; ++ goto out; ++ } ++ ++ mark_inode_dirty(inode); ++ return inode; ++ ++out: ++ clear_nlink(inode); ++ unlock_new_inode(inode); ++fail: ++ iput(inode); ++ if (nid_free) ++ alloc_nid_failed(sbi, ino); ++ return ERR_PTR(err); ++} ++ ++static int is_multimedia_file(const unsigned char *s, const char *sub) ++{ ++ int slen = strlen(s); ++ int sublen = strlen(sub); ++ int ret; ++ ++ if (sublen > slen) ++ return 1; ++ ++ ret = memcmp(s + slen - sublen, sub, sublen); ++ if (ret) { /* compare upper case */ ++ int i; ++ char upper_sub[8]; ++ for (i = 0; i < sublen && i < sizeof(upper_sub); i++) ++ upper_sub[i] = toupper(sub[i]); ++ return memcmp(s + slen - sublen, upper_sub, sublen); ++ } ++ ++ return ret; ++} ++ ++/** ++ * Set multimedia files as cold files for hot/cold data separation ++ */ ++static inline void set_cold_file(struct f2fs_sb_info *sbi, struct inode *inode, ++ const unsigned char *name) ++{ ++ int i; ++ __u8 (*extlist)[8] = sbi->raw_super->extension_list; ++ ++ int count = le32_to_cpu(sbi->raw_super->extension_count); ++ for (i = 0; i < count; i++) { ++ if (!is_multimedia_file(name, extlist[i])) { ++ F2FS_I(inode)->i_advise |= FADVISE_COLD_BIT; ++ break; ++ } ++ } ++} ++ ++static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ++ bool excl) ++{ ++ struct super_block *sb = dir->i_sb; ++ struct f2fs_sb_info *sbi = F2FS_SB(sb); ++ struct inode *inode; ++ nid_t ino = 0; ++ int err; ++ ++ inode = f2fs_new_inode(dir, mode); ++ if (IS_ERR(inode)) ++ return PTR_ERR(inode); ++ ++ if (!test_opt(sbi, DISABLE_EXT_IDENTIFY)) ++ set_cold_file(sbi, inode, dentry->d_name.name); ++ ++ inode->i_op = &f2fs_file_inode_operations; ++ inode->i_fop = &f2fs_file_operations; ++ inode->i_mapping->a_ops = &f2fs_dblock_aops; ++ ino = inode->i_ino; ++ ++ err = f2fs_add_link(dentry, inode); ++ if (err) ++ goto out; ++ ++ alloc_nid_done(sbi, ino); ++ ++ if (!sbi->por_doing) ++ d_instantiate(dentry, inode); ++ unlock_new_inode(inode); ++ ++ f2fs_balance_fs(sbi); ++ return 0; ++out: ++ clear_nlink(inode); ++ unlock_new_inode(inode); ++ iput(inode); ++ alloc_nid_failed(sbi, ino); ++ return err; ++} ++ ++static int f2fs_link(struct dentry *old_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ struct inode *inode = old_dentry->d_inode; ++ struct super_block *sb = dir->i_sb; ++ struct f2fs_sb_info *sbi = F2FS_SB(sb); ++ int err; ++ ++ inode->i_ctime = CURRENT_TIME; ++ atomic_inc(&inode->i_count); ++ ++ set_inode_flag(F2FS_I(inode), FI_INC_LINK); ++ err = f2fs_add_link(dentry, inode); ++ if (err) ++ goto out; ++ ++ d_instantiate(dentry, inode); ++ ++ f2fs_balance_fs(sbi); ++ return 0; ++out: ++ clear_inode_flag(F2FS_I(inode), FI_INC_LINK); ++ iput(inode); ++ return err; ++} ++ ++static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, ++ unsigned int flags) ++{ ++ struct inode *inode = NULL; ++ struct f2fs_dir_entry *de; ++ struct page *page; ++ ++ if (dentry->d_name.len > F2FS_MAX_NAME_LEN) ++ return ERR_PTR(-ENAMETOOLONG); ++ ++ de = f2fs_find_entry(dir, &dentry->d_name, &page); ++ if (de) { ++ nid_t ino = le32_to_cpu(de->ino); ++ kunmap(page); ++ f2fs_put_page(page, 0); ++ ++ inode = f2fs_iget(dir->i_sb, ino); ++ if (IS_ERR(inode)) ++ return ERR_CAST(inode); ++ } ++ ++ return d_splice_alias(inode, dentry); ++} ++ ++static int f2fs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ struct super_block *sb = dir->i_sb; ++ struct f2fs_sb_info *sbi = F2FS_SB(sb); ++ struct inode *inode = dentry->d_inode; ++ struct f2fs_dir_entry *de; ++ struct page *page; ++ int err = -ENOENT; ++ ++ de = f2fs_find_entry(dir, &dentry->d_name, &page); ++ if (!de) ++ goto fail; ++ ++ err = check_orphan_space(sbi); ++ if (err) { ++ kunmap(page); ++ f2fs_put_page(page, 0); ++ goto fail; ++ } ++ ++ f2fs_delete_entry(de, page, inode); ++ ++ /* In order to evict this inode, we set it dirty */ ++ mark_inode_dirty(inode); ++ f2fs_balance_fs(sbi); ++fail: ++ return err; ++} ++ ++static int f2fs_symlink(struct inode *dir, struct dentry *dentry, ++ const char *symname) ++{ ++ struct super_block *sb = dir->i_sb; ++ struct f2fs_sb_info *sbi = F2FS_SB(sb); ++ struct inode *inode; ++ unsigned symlen = strlen(symname) + 1; ++ int err; ++ ++ inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO); ++ if (IS_ERR(inode)) ++ return PTR_ERR(inode); ++ ++ inode->i_op = &f2fs_symlink_inode_operations; ++ inode->i_mapping->a_ops = &f2fs_dblock_aops; ++ ++ err = f2fs_add_link(dentry, inode); ++ if (err) ++ goto out; ++ ++ err = page_symlink(inode, symname, symlen); ++ alloc_nid_done(sbi, inode->i_ino); ++ ++ d_instantiate(dentry, inode); ++ unlock_new_inode(inode); ++ ++ f2fs_balance_fs(sbi); ++ ++ return err; ++out: ++ clear_nlink(inode); ++ unlock_new_inode(inode); ++ iput(inode); ++ alloc_nid_failed(sbi, inode->i_ino); ++ return err; ++} ++ ++static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); ++ struct inode *inode; ++ int err; ++ ++ inode = f2fs_new_inode(dir, S_IFDIR | mode); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ return err; ++ ++ inode->i_op = &f2fs_dir_inode_operations; ++ inode->i_fop = &f2fs_dir_operations; ++ inode->i_mapping->a_ops = &f2fs_dblock_aops; ++ mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS | __GFP_ZERO); ++ ++ set_inode_flag(F2FS_I(inode), FI_INC_LINK); ++ err = f2fs_add_link(dentry, inode); ++ if (err) ++ goto out_fail; ++ ++ alloc_nid_done(sbi, inode->i_ino); ++ ++ d_instantiate(dentry, inode); ++ unlock_new_inode(inode); ++ ++ f2fs_balance_fs(sbi); ++ return 0; ++ ++out_fail: ++ clear_inode_flag(F2FS_I(inode), FI_INC_LINK); ++ clear_nlink(inode); ++ unlock_new_inode(inode); ++ iput(inode); ++ alloc_nid_failed(sbi, inode->i_ino); ++ return err; ++} ++ ++static int f2fs_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ struct inode *inode = dentry->d_inode; ++ if (f2fs_empty_dir(inode)) ++ return f2fs_unlink(dir, dentry); ++ return -ENOTEMPTY; ++} ++ ++static int f2fs_mknod(struct inode *dir, struct dentry *dentry, ++ umode_t mode, dev_t rdev) ++{ ++ struct super_block *sb = dir->i_sb; ++ struct f2fs_sb_info *sbi = F2FS_SB(sb); ++ struct inode *inode; ++ int err = 0; ++ ++ if (!new_valid_dev(rdev)) ++ return -EINVAL; ++ ++ inode = f2fs_new_inode(dir, mode); ++ if (IS_ERR(inode)) ++ return PTR_ERR(inode); ++ ++ init_special_inode(inode, inode->i_mode, rdev); ++ inode->i_op = &f2fs_special_inode_operations; ++ ++ err = f2fs_add_link(dentry, inode); ++ if (err) ++ goto out; ++ ++ alloc_nid_done(sbi, inode->i_ino); ++ d_instantiate(dentry, inode); ++ unlock_new_inode(inode); ++ ++ f2fs_balance_fs(sbi); ++ ++ return 0; ++out: ++ clear_nlink(inode); ++ unlock_new_inode(inode); ++ iput(inode); ++ alloc_nid_failed(sbi, inode->i_ino); ++ return err; ++} ++ ++static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ++ struct inode *new_dir, struct dentry *new_dentry) ++{ ++ struct super_block *sb = old_dir->i_sb; ++ struct f2fs_sb_info *sbi = F2FS_SB(sb); ++ struct inode *old_inode = old_dentry->d_inode; ++ struct inode *new_inode = new_dentry->d_inode; ++ struct page *old_dir_page; ++ struct page *old_page; ++ struct f2fs_dir_entry *old_dir_entry = NULL; ++ struct f2fs_dir_entry *old_entry; ++ struct f2fs_dir_entry *new_entry; ++ int err = -ENOENT; ++ ++ old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page); ++ if (!old_entry) ++ goto out; ++ ++ if (S_ISDIR(old_inode->i_mode)) { ++ err = -EIO; ++ old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page); ++ if (!old_dir_entry) ++ goto out_old; ++ } ++ ++ mutex_lock_op(sbi, RENAME); ++ ++ if (new_inode) { ++ struct page *new_page; ++ ++ err = -ENOTEMPTY; ++ if (old_dir_entry && !f2fs_empty_dir(new_inode)) ++ goto out_dir; ++ ++ err = -ENOENT; ++ new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name, ++ &new_page); ++ if (!new_entry) ++ goto out_dir; ++ ++ f2fs_set_link(new_dir, new_entry, new_page, old_inode); ++ ++ new_inode->i_ctime = CURRENT_TIME; ++ if (old_dir_entry) ++ drop_nlink(new_inode); ++ drop_nlink(new_inode); ++ if (!new_inode->i_nlink) ++ add_orphan_inode(sbi, new_inode->i_ino); ++ f2fs_write_inode(new_inode, NULL); ++ } else { ++ err = f2fs_add_link(new_dentry, old_inode); ++ if (err) ++ goto out_dir; ++ ++ if (old_dir_entry) { ++ inc_nlink(new_dir); ++ f2fs_write_inode(new_dir, NULL); ++ } ++ } ++ ++ old_inode->i_ctime = CURRENT_TIME; ++ set_inode_flag(F2FS_I(old_inode), FI_NEED_CP); ++ mark_inode_dirty(old_inode); ++ ++ f2fs_delete_entry(old_entry, old_page, NULL); ++ ++ if (old_dir_entry) { ++ if (old_dir != new_dir) { ++ f2fs_set_link(old_inode, old_dir_entry, ++ old_dir_page, new_dir); ++ } else { ++ kunmap(old_dir_page); ++ f2fs_put_page(old_dir_page, 0); ++ } ++ drop_nlink(old_dir); ++ f2fs_write_inode(old_dir, NULL); ++ } ++ ++ mutex_unlock_op(sbi, RENAME); ++ ++ f2fs_balance_fs(sbi); ++ return 0; ++ ++out_dir: ++ if (old_dir_entry) { ++ kunmap(old_dir_page); ++ f2fs_put_page(old_dir_page, 0); ++ } ++ mutex_unlock_op(sbi, RENAME); ++out_old: ++ kunmap(old_page); ++ f2fs_put_page(old_page, 0); ++out: ++ return err; ++} ++ ++const struct inode_operations f2fs_dir_inode_operations = { ++ .create = f2fs_create, ++ .lookup = f2fs_lookup, ++ .link = f2fs_link, ++ .unlink = f2fs_unlink, ++ .symlink = f2fs_symlink, ++ .mkdir = f2fs_mkdir, ++ .rmdir = f2fs_rmdir, ++ .mknod = f2fs_mknod, ++ .rename = f2fs_rename, ++ .setattr = f2fs_setattr, ++ .get_acl = f2fs_get_acl, ++#ifdef CONFIG_F2FS_FS_XATTR ++ .setxattr = generic_setxattr, ++ .getxattr = generic_getxattr, ++ .listxattr = f2fs_listxattr, ++ .removexattr = generic_removexattr, ++#endif ++}; ++ ++const struct inode_operations f2fs_symlink_inode_operations = { ++ .readlink = generic_readlink, ++ .follow_link = page_follow_link_light, ++ .put_link = page_put_link, ++ .setattr = f2fs_setattr, ++#ifdef CONFIG_F2FS_FS_XATTR ++ .setxattr = generic_setxattr, ++ .getxattr = generic_getxattr, ++ .listxattr = f2fs_listxattr, ++ .removexattr = generic_removexattr, ++#endif ++}; ++ ++const struct inode_operations f2fs_special_inode_operations = { ++ .setattr = f2fs_setattr, ++ .get_acl = f2fs_get_acl, ++#ifdef CONFIG_F2FS_FS_XATTR ++ .setxattr = generic_setxattr, ++ .getxattr = generic_getxattr, ++ .listxattr = f2fs_listxattr, ++ .removexattr = generic_removexattr, ++#endif ++}; diff --git a/patches/linux-3.7-rc6/0109-f2fs-add-core-directory-operations.patch b/patches/linux-3.7-rc6/0109-f2fs-add-core-directory-operations.patch new file mode 100644 index 0000000..ac2824b --- /dev/null +++ b/patches/linux-3.7-rc6/0109-f2fs-add-core-directory-operations.patch @@ -0,0 +1,782 @@ +From 39207d517eb7f9f43205c6fc2f0c3a9a6d398f97 Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:31:34 +0000 +Subject: [PATCH] f2fs: add core directory operations + +This adds core functions to find, add, delete, and link dentries. + +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/f2fs/dir.c | 657 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/f2fs/hash.c | 98 +++++++++ + 2 files changed, 755 insertions(+) + create mode 100644 fs/f2fs/dir.c + create mode 100644 fs/f2fs/hash.c + +diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c +new file mode 100644 +index 0000000..f3de333 +--- /dev/null ++++ b/fs/f2fs/dir.c +@@ -0,0 +1,657 @@ ++/** ++ * fs/f2fs/dir.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/fs.h> ++#include <linux/f2fs_fs.h> ++#include "f2fs.h" ++#include "acl.h" ++ ++static unsigned long dir_blocks(struct inode *inode) ++{ ++ return ((unsigned long long) (i_size_read(inode) + PAGE_CACHE_SIZE - 1)) ++ >> PAGE_CACHE_SHIFT; ++} ++ ++static unsigned int dir_buckets(unsigned int level) ++{ ++ if (level < MAX_DIR_HASH_DEPTH / 2) ++ return 1 << level; ++ else ++ return 1 << ((MAX_DIR_HASH_DEPTH / 2) - 1); ++} ++ ++static unsigned int bucket_blocks(unsigned int level) ++{ ++ if (level < MAX_DIR_HASH_DEPTH / 2) ++ return 2; ++ else ++ return 4; ++} ++ ++static unsigned char f2fs_filetype_table[F2FS_FT_MAX] = { ++ [F2FS_FT_UNKNOWN] = DT_UNKNOWN, ++ [F2FS_FT_REG_FILE] = DT_REG, ++ [F2FS_FT_DIR] = DT_DIR, ++ [F2FS_FT_CHRDEV] = DT_CHR, ++ [F2FS_FT_BLKDEV] = DT_BLK, ++ [F2FS_FT_FIFO] = DT_FIFO, ++ [F2FS_FT_SOCK] = DT_SOCK, ++ [F2FS_FT_SYMLINK] = DT_LNK, ++}; ++ ++#define S_SHIFT 12 ++static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = { ++ [S_IFREG >> S_SHIFT] = F2FS_FT_REG_FILE, ++ [S_IFDIR >> S_SHIFT] = F2FS_FT_DIR, ++ [S_IFCHR >> S_SHIFT] = F2FS_FT_CHRDEV, ++ [S_IFBLK >> S_SHIFT] = F2FS_FT_BLKDEV, ++ [S_IFIFO >> S_SHIFT] = F2FS_FT_FIFO, ++ [S_IFSOCK >> S_SHIFT] = F2FS_FT_SOCK, ++ [S_IFLNK >> S_SHIFT] = F2FS_FT_SYMLINK, ++}; ++ ++static void set_de_type(struct f2fs_dir_entry *de, struct inode *inode) ++{ ++ mode_t mode = inode->i_mode; ++ de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT]; ++} ++ ++static unsigned long dir_block_index(unsigned int level, unsigned int idx) ++{ ++ unsigned long i; ++ unsigned long bidx = 0; ++ ++ for (i = 0; i < level; i++) ++ bidx += dir_buckets(i) * bucket_blocks(i); ++ bidx += idx * bucket_blocks(level); ++ return bidx; ++} ++ ++static bool early_match_name(const char *name, int namelen, ++ f2fs_hash_t namehash, struct f2fs_dir_entry *de) ++{ ++ if (le16_to_cpu(de->name_len) != namelen) ++ return false; ++ ++ if (le32_to_cpu(de->hash_code) != namehash) ++ return false; ++ ++ return true; ++} ++ ++static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, ++ const char *name, int namelen, int *max_slots, ++ f2fs_hash_t namehash, struct page **res_page) ++{ ++ struct f2fs_dir_entry *de; ++ unsigned long bit_pos, end_pos, next_pos; ++ struct f2fs_dentry_block *dentry_blk = kmap(dentry_page); ++ int slots; ++ ++ bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, ++ NR_DENTRY_IN_BLOCK, 0); ++ while (bit_pos < NR_DENTRY_IN_BLOCK) { ++ de = &dentry_blk->dentry[bit_pos]; ++ slots = (le16_to_cpu(de->name_len) + F2FS_NAME_LEN - 1) / ++ F2FS_NAME_LEN; ++ ++ if (early_match_name(name, namelen, namehash, de)) { ++ if (!memcmp(dentry_blk->filename[bit_pos], ++ name, namelen)) { ++ *res_page = dentry_page; ++ goto found; ++ } ++ } ++ next_pos = bit_pos + slots; ++ bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, ++ NR_DENTRY_IN_BLOCK, next_pos); ++ if (bit_pos >= NR_DENTRY_IN_BLOCK) ++ end_pos = NR_DENTRY_IN_BLOCK; ++ else ++ end_pos = bit_pos; ++ if (*max_slots < end_pos - next_pos) ++ *max_slots = end_pos - next_pos; ++ } ++ ++ de = NULL; ++ kunmap(dentry_page); ++found: ++ return de; ++} ++ ++static struct f2fs_dir_entry *find_in_level(struct inode *dir, ++ unsigned int level, const char *name, int namelen, ++ f2fs_hash_t namehash, struct page **res_page) ++{ ++ int s = (namelen + F2FS_NAME_LEN - 1) / F2FS_NAME_LEN; ++ unsigned int nbucket, nblock; ++ unsigned int bidx, end_block; ++ struct page *dentry_page; ++ struct f2fs_dir_entry *de = NULL; ++ bool room = false; ++ int max_slots = 0; ++ ++ BUG_ON(level > MAX_DIR_HASH_DEPTH); ++ ++ nbucket = dir_buckets(level); ++ nblock = bucket_blocks(level); ++ ++ bidx = dir_block_index(level, namehash % nbucket); ++ end_block = bidx + nblock; ++ ++ for (; bidx < end_block; bidx++) { ++ /* no need to allocate new dentry pages to all the indices */ ++ dentry_page = find_data_page(dir, bidx); ++ if (IS_ERR(dentry_page)) { ++ room = true; ++ continue; ++ } ++ ++ de = find_in_block(dentry_page, name, namelen, ++ &max_slots, namehash, res_page); ++ if (de) ++ break; ++ ++ if (max_slots >= s) ++ room = true; ++ f2fs_put_page(dentry_page, 0); ++ } ++ ++ if (!de && room && F2FS_I(dir)->chash != namehash) { ++ F2FS_I(dir)->chash = namehash; ++ F2FS_I(dir)->clevel = level; ++ } ++ ++ return de; ++} ++ ++/* ++ * Find an entry in the specified directory with the wanted name. ++ * It returns the page where the entry was found (as a parameter - res_page), ++ * and the entry itself. Page is returned mapped and unlocked. ++ * Entry is guaranteed to be valid. ++ */ ++struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, ++ struct qstr *child, struct page **res_page) ++{ ++ const char *name = child->name; ++ int namelen = child->len; ++ unsigned long npages = dir_blocks(dir); ++ struct f2fs_dir_entry *de = NULL; ++ f2fs_hash_t name_hash; ++ unsigned int max_depth; ++ unsigned int level; ++ ++ if (npages == 0) ++ return NULL; ++ ++ *res_page = NULL; ++ ++ name_hash = f2fs_dentry_hash(name, namelen); ++ max_depth = F2FS_I(dir)->current_depth; ++ ++ for (level = 0; level < max_depth; level++) { ++ de = find_in_level(dir, level, name, ++ namelen, name_hash, res_page); ++ if (de) ++ break; ++ } ++ if (!de && F2FS_I(dir)->chash != name_hash) { ++ F2FS_I(dir)->chash = name_hash; ++ F2FS_I(dir)->clevel = level - 1; ++ } ++ return de; ++} ++ ++struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p) ++{ ++ struct page *page = NULL; ++ struct f2fs_dir_entry *de = NULL; ++ struct f2fs_dentry_block *dentry_blk = NULL; ++ ++ page = get_lock_data_page(dir, 0); ++ if (IS_ERR(page)) ++ return NULL; ++ ++ dentry_blk = kmap(page); ++ de = &dentry_blk->dentry[1]; ++ *p = page; ++ unlock_page(page); ++ return de; ++} ++ ++void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, ++ struct page *page, struct inode *inode) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); ++ ++ mutex_lock_op(sbi, DENTRY_OPS); ++ lock_page(page); ++ wait_on_page_writeback(page); ++ de->ino = cpu_to_le32(inode->i_ino); ++ set_de_type(de, inode); ++ kunmap(page); ++ set_page_dirty(page); ++ dir->i_mtime = dir->i_ctime = CURRENT_TIME; ++ mark_inode_dirty(dir); ++ f2fs_put_page(page, 1); ++ mutex_unlock_op(sbi, DENTRY_OPS); ++} ++ ++void init_dent_inode(struct dentry *dentry, struct page *ipage) ++{ ++ struct inode *dir = dentry->d_parent->d_inode; ++ struct f2fs_node *rn; ++ ++ if (IS_ERR(ipage)) ++ return; ++ ++ wait_on_page_writeback(ipage); ++ ++ /* copy dentry info. to this inode page */ ++ rn = (struct f2fs_node *)page_address(ipage); ++ rn->i.i_pino = cpu_to_le32(dir->i_ino); ++ rn->i.i_namelen = cpu_to_le32(dentry->d_name.len); ++ memcpy(rn->i.i_name, dentry->d_name.name, dentry->d_name.len); ++ set_page_dirty(ipage); ++} ++ ++static int init_inode_metadata(struct inode *inode, struct dentry *dentry) ++{ ++ struct inode *dir = dentry->d_parent->d_inode; ++ ++ if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { ++ int err; ++ err = new_inode_page(inode, dentry); ++ if (err) ++ return err; ++ ++ if (S_ISDIR(inode->i_mode)) { ++ err = f2fs_make_empty(inode, dir); ++ if (err) { ++ remove_inode_page(inode); ++ return err; ++ } ++ } ++ ++ err = f2fs_init_acl(inode, dir); ++ if (err) { ++ remove_inode_page(inode); ++ return err; ++ } ++ } else { ++ struct page *ipage; ++ ipage = get_node_page(F2FS_SB(dir->i_sb), inode->i_ino); ++ if (IS_ERR(ipage)) ++ return PTR_ERR(ipage); ++ init_dent_inode(dentry, ipage); ++ f2fs_put_page(ipage, 1); ++ } ++ if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) { ++ inc_nlink(inode); ++ f2fs_write_inode(inode, NULL); ++ } ++ return 0; ++} ++ ++static void update_parent_metadata(struct inode *dir, struct inode *inode, ++ unsigned int current_depth) ++{ ++ bool need_dir_update = false; ++ ++ if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { ++ if (S_ISDIR(inode->i_mode)) { ++ inc_nlink(dir); ++ need_dir_update = true; ++ } ++ clear_inode_flag(F2FS_I(inode), FI_NEW_INODE); ++ } ++ dir->i_mtime = dir->i_ctime = CURRENT_TIME; ++ if (F2FS_I(dir)->current_depth != current_depth) { ++ F2FS_I(dir)->current_depth = current_depth; ++ need_dir_update = true; ++ } ++ ++ if (need_dir_update) ++ f2fs_write_inode(dir, NULL); ++ else ++ mark_inode_dirty(dir); ++ ++ if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) ++ clear_inode_flag(F2FS_I(inode), FI_INC_LINK); ++} ++ ++static int room_for_filename(struct f2fs_dentry_block *dentry_blk, int slots) ++{ ++ int bit_start = 0; ++ int zero_start, zero_end; ++next: ++ zero_start = find_next_zero_bit_le(&dentry_blk->dentry_bitmap, ++ NR_DENTRY_IN_BLOCK, ++ bit_start); ++ if (zero_start >= NR_DENTRY_IN_BLOCK) ++ return NR_DENTRY_IN_BLOCK; ++ ++ zero_end = find_next_bit_le(&dentry_blk->dentry_bitmap, ++ NR_DENTRY_IN_BLOCK, ++ zero_start); ++ if (zero_end - zero_start >= slots) ++ return zero_start; ++ ++ bit_start = zero_end + 1; ++ ++ if (zero_end + 1 >= NR_DENTRY_IN_BLOCK) ++ return NR_DENTRY_IN_BLOCK; ++ goto next; ++} ++ ++int f2fs_add_link(struct dentry *dentry, struct inode *inode) ++{ ++ unsigned int bit_pos; ++ unsigned int level; ++ unsigned int current_depth; ++ unsigned long bidx, block; ++ f2fs_hash_t dentry_hash; ++ struct f2fs_dir_entry *de; ++ unsigned int nbucket, nblock; ++ struct inode *dir = dentry->d_parent->d_inode; ++ struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); ++ const char *name = dentry->d_name.name; ++ int namelen = dentry->d_name.len; ++ struct page *dentry_page = NULL; ++ struct f2fs_dentry_block *dentry_blk = NULL; ++ int slots = (namelen + F2FS_NAME_LEN - 1) / F2FS_NAME_LEN; ++ int err = 0; ++ int i; ++ ++ dentry_hash = f2fs_dentry_hash(name, dentry->d_name.len); ++ level = 0; ++ current_depth = F2FS_I(dir)->current_depth; ++ if (F2FS_I(dir)->chash == dentry_hash) { ++ level = F2FS_I(dir)->clevel; ++ F2FS_I(dir)->chash = 0; ++ } ++ ++start: ++ if (current_depth == MAX_DIR_HASH_DEPTH) ++ return -ENOSPC; ++ ++ /* Increase the depth, if required */ ++ if (level == current_depth) ++ ++current_depth; ++ ++ nbucket = dir_buckets(level); ++ nblock = bucket_blocks(level); ++ ++ bidx = dir_block_index(level, (dentry_hash % nbucket)); ++ ++ for (block = bidx; block <= (bidx + nblock - 1); block++) { ++ mutex_lock_op(sbi, DENTRY_OPS); ++ dentry_page = get_new_data_page(dir, block, true); ++ if (IS_ERR(dentry_page)) { ++ mutex_unlock_op(sbi, DENTRY_OPS); ++ return PTR_ERR(dentry_page); ++ } ++ ++ dentry_blk = kmap(dentry_page); ++ bit_pos = room_for_filename(dentry_blk, slots); ++ if (bit_pos < NR_DENTRY_IN_BLOCK) ++ goto add_dentry; ++ ++ kunmap(dentry_page); ++ f2fs_put_page(dentry_page, 1); ++ mutex_unlock_op(sbi, DENTRY_OPS); ++ } ++ ++ /* Move to next level to find the empty slot for new dentry */ ++ ++level; ++ goto start; ++add_dentry: ++ err = init_inode_metadata(inode, dentry); ++ if (err) ++ goto fail; ++ ++ wait_on_page_writeback(dentry_page); ++ ++ de = &dentry_blk->dentry[bit_pos]; ++ de->hash_code = cpu_to_le32(dentry_hash); ++ de->name_len = cpu_to_le16(namelen); ++ memcpy(dentry_blk->filename[bit_pos], name, namelen); ++ de->ino = cpu_to_le32(inode->i_ino); ++ set_de_type(de, inode); ++ for (i = 0; i < slots; i++) ++ test_and_set_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); ++ set_page_dirty(dentry_page); ++ update_parent_metadata(dir, inode, current_depth); ++fail: ++ kunmap(dentry_page); ++ f2fs_put_page(dentry_page, 1); ++ mutex_unlock_op(sbi, DENTRY_OPS); ++ return err; ++} ++ ++/** ++ * It only removes the dentry from the dentry page,corresponding name ++ * entry in name page does not need to be touched during deletion. ++ */ ++void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, ++ struct inode *inode) ++{ ++ struct f2fs_dentry_block *dentry_blk; ++ unsigned int bit_pos; ++ struct address_space *mapping = page->mapping; ++ struct inode *dir = mapping->host; ++ struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); ++ int slots = (le16_to_cpu(dentry->name_len) + F2FS_NAME_LEN - 1) / ++ F2FS_NAME_LEN; ++ void *kaddr = page_address(page); ++ int i; ++ ++ mutex_lock_op(sbi, DENTRY_OPS); ++ ++ lock_page(page); ++ wait_on_page_writeback(page); ++ ++ dentry_blk = (struct f2fs_dentry_block *)kaddr; ++ bit_pos = dentry - (struct f2fs_dir_entry *)dentry_blk->dentry; ++ for (i = 0; i < slots; i++) ++ test_and_clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); ++ ++ /* Let's check and deallocate this dentry page */ ++ bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, ++ NR_DENTRY_IN_BLOCK, ++ 0); ++ kunmap(page); /* kunmap - pair of f2fs_find_entry */ ++ set_page_dirty(page); ++ ++ dir->i_ctime = dir->i_mtime = CURRENT_TIME; ++ ++ if (inode && S_ISDIR(inode->i_mode)) { ++ drop_nlink(dir); ++ f2fs_write_inode(dir, NULL); ++ } else { ++ mark_inode_dirty(dir); ++ } ++ ++ if (inode) { ++ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; ++ drop_nlink(inode); ++ if (S_ISDIR(inode->i_mode)) { ++ drop_nlink(inode); ++ i_size_write(inode, 0); ++ } ++ f2fs_write_inode(inode, NULL); ++ if (inode->i_nlink == 0) ++ add_orphan_inode(sbi, inode->i_ino); ++ } ++ ++ if (bit_pos == NR_DENTRY_IN_BLOCK) { ++ loff_t page_offset; ++ truncate_hole(dir, page->index, page->index + 1); ++ clear_page_dirty_for_io(page); ++ ClearPageUptodate(page); ++ dec_page_count(sbi, F2FS_DIRTY_DENTS); ++ inode_dec_dirty_dents(dir); ++ page_offset = page->index << PAGE_CACHE_SHIFT; ++ f2fs_put_page(page, 1); ++ } else { ++ f2fs_put_page(page, 1); ++ } ++ mutex_unlock_op(sbi, DENTRY_OPS); ++} ++ ++int f2fs_make_empty(struct inode *inode, struct inode *parent) ++{ ++ struct page *dentry_page; ++ struct f2fs_dentry_block *dentry_blk; ++ struct f2fs_dir_entry *de; ++ void *kaddr; ++ ++ dentry_page = get_new_data_page(inode, 0, true); ++ if (IS_ERR(dentry_page)) ++ return PTR_ERR(dentry_page); ++ ++ kaddr = kmap_atomic(dentry_page); ++ dentry_blk = (struct f2fs_dentry_block *)kaddr; ++ ++ de = &dentry_blk->dentry[0]; ++ de->name_len = cpu_to_le16(1); ++ de->hash_code = 0; ++ de->ino = cpu_to_le32(inode->i_ino); ++ memcpy(dentry_blk->filename[0], ".", 1); ++ set_de_type(de, inode); ++ ++ de = &dentry_blk->dentry[1]; ++ de->hash_code = 0; ++ de->name_len = cpu_to_le16(2); ++ de->ino = cpu_to_le32(parent->i_ino); ++ memcpy(dentry_blk->filename[1], "..", 2); ++ set_de_type(de, inode); ++ ++ test_and_set_bit_le(0, &dentry_blk->dentry_bitmap); ++ test_and_set_bit_le(1, &dentry_blk->dentry_bitmap); ++ kunmap_atomic(kaddr); ++ ++ set_page_dirty(dentry_page); ++ f2fs_put_page(dentry_page, 1); ++ return 0; ++} ++ ++bool f2fs_empty_dir(struct inode *dir) ++{ ++ unsigned long bidx; ++ struct page *dentry_page; ++ unsigned int bit_pos; ++ struct f2fs_dentry_block *dentry_blk; ++ unsigned long nblock = dir_blocks(dir); ++ ++ for (bidx = 0; bidx < nblock; bidx++) { ++ void *kaddr; ++ dentry_page = get_lock_data_page(dir, bidx); ++ if (IS_ERR(dentry_page)) { ++ if (PTR_ERR(dentry_page) == -ENOENT) ++ continue; ++ else ++ return false; ++ } ++ ++ kaddr = kmap_atomic(dentry_page); ++ dentry_blk = (struct f2fs_dentry_block *)kaddr; ++ if (bidx == 0) ++ bit_pos = 2; ++ else ++ bit_pos = 0; ++ bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, ++ NR_DENTRY_IN_BLOCK, ++ bit_pos); ++ kunmap_atomic(kaddr); ++ ++ f2fs_put_page(dentry_page, 1); ++ ++ if (bit_pos < NR_DENTRY_IN_BLOCK) ++ return false; ++ } ++ return true; ++} ++ ++static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir) ++{ ++ unsigned long pos = file->f_pos; ++ struct inode *inode = file->f_dentry->d_inode; ++ unsigned long npages = dir_blocks(inode); ++ unsigned char *types = NULL; ++ unsigned int bit_pos = 0, start_bit_pos = 0; ++ int over = 0; ++ struct f2fs_dentry_block *dentry_blk = NULL; ++ struct f2fs_dir_entry *de = NULL; ++ struct page *dentry_page = NULL; ++ unsigned int n = 0; ++ unsigned char *ptr = NULL; ++ unsigned char d_type = DT_UNKNOWN; ++ int slots; ++ ++ types = f2fs_filetype_table; ++ bit_pos = (pos % NR_DENTRY_IN_BLOCK); ++ n = (pos / NR_DENTRY_IN_BLOCK); ++ ++ for ( ; n < npages; n++) { ++ dentry_page = get_lock_data_page(inode, n); ++ if (IS_ERR(dentry_page)) ++ continue; ++ ++ start_bit_pos = bit_pos; ++ dentry_blk = kmap(dentry_page); ++ while (bit_pos < NR_DENTRY_IN_BLOCK) { ++ d_type = DT_UNKNOWN; ++ bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, ++ NR_DENTRY_IN_BLOCK, ++ bit_pos); ++ if (bit_pos >= NR_DENTRY_IN_BLOCK) ++ break; ++ ++ de = &dentry_blk->dentry[bit_pos]; ++ if (types && de->file_type < F2FS_FT_MAX) ++ d_type = types[de->file_type]; ++ ++ ptr = dentry_blk->filename[bit_pos]; ++ over = filldir(dirent, ++ dentry_blk->filename[bit_pos], ++ le16_to_cpu(de->name_len), ++ (n * NR_DENTRY_IN_BLOCK) + bit_pos, ++ le32_to_cpu(de->ino), d_type); ++ if (over) { ++ file->f_pos += bit_pos - start_bit_pos; ++ goto success; ++ } ++ slots = (le16_to_cpu(de->name_len) + F2FS_NAME_LEN - 1) ++ / F2FS_NAME_LEN; ++ bit_pos += slots; ++ } ++ bit_pos = 0; ++ file->f_pos = (n + 1) * NR_DENTRY_IN_BLOCK; ++ kunmap(dentry_page); ++ f2fs_put_page(dentry_page, 1); ++ dentry_page = NULL; ++ } ++success: ++ if (dentry_page && !IS_ERR(dentry_page)) { ++ kunmap(dentry_page); ++ f2fs_put_page(dentry_page, 1); ++ } ++ ++ return 0; ++} ++ ++const struct file_operations f2fs_dir_operations = { ++ .read = generic_read_dir, ++ .readdir = f2fs_readdir, ++ .fsync = f2fs_sync_file, ++ .unlocked_ioctl = f2fs_ioctl, ++}; +diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c +new file mode 100644 +index 0000000..098a196 +--- /dev/null ++++ b/fs/f2fs/hash.c +@@ -0,0 +1,98 @@ ++/** ++ * fs/f2fs/hash.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * Portions of this code from linux/fs/ext3/hash.c ++ * ++ * Copyright (C) 2002 by Theodore Ts'o ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/types.h> ++#include <linux/fs.h> ++#include <linux/f2fs_fs.h> ++#include <linux/cryptohash.h> ++#include <linux/pagemap.h> ++ ++#include "f2fs.h" ++ ++/* ++ * Hashing code copied from ext3 ++ */ ++#define DELTA 0x9E3779B9 ++ ++static void TEA_transform(unsigned int buf[4], unsigned int const in[]) ++{ ++ __u32 sum = 0; ++ __u32 b0 = buf[0], b1 = buf[1]; ++ __u32 a = in[0], b = in[1], c = in[2], d = in[3]; ++ int n = 16; ++ ++ do { ++ sum += DELTA; ++ b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); ++ b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); ++ } while (--n); ++ ++ buf[0] += b0; ++ buf[1] += b1; ++} ++ ++static void str2hashbuf(const char *msg, int len, unsigned int *buf, int num) ++{ ++ unsigned pad, val; ++ int i; ++ ++ pad = (__u32)len | ((__u32)len << 8); ++ pad |= pad << 16; ++ ++ val = pad; ++ if (len > num * 4) ++ len = num * 4; ++ for (i = 0; i < len; i++) { ++ if ((i % 4) == 0) ++ val = pad; ++ val = msg[i] + (val << 8); ++ if ((i % 4) == 3) { ++ *buf++ = val; ++ val = pad; ++ num--; ++ } ++ } ++ if (--num >= 0) ++ *buf++ = val; ++ while (--num >= 0) ++ *buf++ = pad; ++} ++ ++f2fs_hash_t f2fs_dentry_hash(const char *name, int len) ++{ ++ __u32 hash, minor_hash; ++ f2fs_hash_t f2fs_hash; ++ const char *p; ++ __u32 in[8], buf[4]; ++ ++ /* Initialize the default seed for the hash checksum functions */ ++ buf[0] = 0x67452301; ++ buf[1] = 0xefcdab89; ++ buf[2] = 0x98badcfe; ++ buf[3] = 0x10325476; ++ ++ p = name; ++ while (len > 0) { ++ str2hashbuf(p, len, in, 4); ++ TEA_transform(buf, in); ++ len -= 16; ++ p += 16; ++ } ++ hash = buf[0]; ++ minor_hash = buf[1]; ++ ++ f2fs_hash = hash; ++ f2fs_hash &= ~F2FS_HASH_COL_BIT; ++ return f2fs_hash; ++} diff --git a/patches/linux-3.7-rc6/0110-f2fs-add-xattr-and-acl-functionalities.patch b/patches/linux-3.7-rc6/0110-f2fs-add-xattr-and-acl-functionalities.patch new file mode 100644 index 0000000..eead241 --- /dev/null +++ b/patches/linux-3.7-rc6/0110-f2fs-add-xattr-and-acl-functionalities.patch @@ -0,0 +1,1102 @@ +From 8e21f5b0090aea281121c14542c55c7043e5168b Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:31:46 +0000 +Subject: [PATCH] f2fs: add xattr and acl functionalities + +This implements xattr and acl functionalities. + +- F2FS uses a node page to contain use extended attributes. + +Signed-off-by: Changman Lee <cm224.lee@samsung.com> +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/f2fs/acl.c | 465 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/f2fs/acl.h | 57 +++++++ + fs/f2fs/xattr.c | 389 ++++++++++++++++++++++++++++++++++++++++++++++ + fs/f2fs/xattr.h | 145 +++++++++++++++++ + 4 files changed, 1056 insertions(+) + create mode 100644 fs/f2fs/acl.c + create mode 100644 fs/f2fs/acl.h + create mode 100644 fs/f2fs/xattr.c + create mode 100644 fs/f2fs/xattr.h + +diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c +new file mode 100644 +index 0000000..dff2a2b +--- /dev/null ++++ b/fs/f2fs/acl.c +@@ -0,0 +1,465 @@ ++/** ++ * fs/f2fs/acl.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * Portions of this code from linux/fs/ext2/acl.c ++ * ++ * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/f2fs_fs.h> ++#include "f2fs.h" ++#include "xattr.h" ++#include "acl.h" ++ ++#define get_inode_mode(i) ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \ ++ (F2FS_I(i)->i_acl_mode) : ((i)->i_mode)) ++ ++static inline size_t f2fs_acl_size(int count) ++{ ++ if (count <= 4) { ++ return sizeof(struct f2fs_acl_header) + ++ count * sizeof(struct f2fs_acl_entry_short); ++ } else { ++ return sizeof(struct f2fs_acl_header) + ++ 4 * sizeof(struct f2fs_acl_entry_short) + ++ (count - 4) * sizeof(struct f2fs_acl_entry); ++ } ++} ++ ++static inline int f2fs_acl_count(size_t size) ++{ ++ ssize_t s; ++ size -= sizeof(struct f2fs_acl_header); ++ s = size - 4 * sizeof(struct f2fs_acl_entry_short); ++ if (s < 0) { ++ if (size % sizeof(struct f2fs_acl_entry_short)) ++ return -1; ++ return size / sizeof(struct f2fs_acl_entry_short); ++ } else { ++ if (s % sizeof(struct f2fs_acl_entry)) ++ return -1; ++ return s / sizeof(struct f2fs_acl_entry) + 4; ++ } ++} ++ ++static struct posix_acl *f2fs_acl_from_disk(const char *value, size_t size) ++{ ++ int i, count; ++ struct posix_acl *acl; ++ struct f2fs_acl_header *hdr = (struct f2fs_acl_header *)value; ++ struct f2fs_acl_entry *entry = (struct f2fs_acl_entry *)(hdr + 1); ++ const char *end = value + size; ++ ++ if (hdr->a_version != cpu_to_le32(F2FS_ACL_VERSION)) ++ return ERR_PTR(-EINVAL); ++ ++ count = f2fs_acl_count(size); ++ if (count < 0) ++ return ERR_PTR(-EINVAL); ++ if (count == 0) ++ return NULL; ++ ++ acl = posix_acl_alloc(count, GFP_KERNEL); ++ if (!acl) ++ return ERR_PTR(-ENOMEM); ++ ++ for (i = 0; i < count; i++) { ++ ++ if ((char *)entry > end) ++ goto fail; ++ ++ acl->a_entries[i].e_tag = le16_to_cpu(entry->e_tag); ++ acl->a_entries[i].e_perm = le16_to_cpu(entry->e_perm); ++ ++ switch (acl->a_entries[i].e_tag) { ++ case ACL_USER_OBJ: ++ case ACL_GROUP_OBJ: ++ case ACL_MASK: ++ case ACL_OTHER: ++ acl->a_entries[i].e_id = ACL_UNDEFINED_ID; ++ entry = (struct f2fs_acl_entry *)((char *)entry + ++ sizeof(struct f2fs_acl_entry_short)); ++ break; ++ ++ case ACL_USER: ++ acl->a_entries[i].e_uid = ++ make_kuid(&init_user_ns, ++ le32_to_cpu(entry->e_id)); ++ entry = (struct f2fs_acl_entry *)((char *)entry + ++ sizeof(struct f2fs_acl_entry)); ++ break; ++ case ACL_GROUP: ++ acl->a_entries[i].e_gid = ++ make_kgid(&init_user_ns, ++ le32_to_cpu(entry->e_id)); ++ entry = (struct f2fs_acl_entry *)((char *)entry + ++ sizeof(struct f2fs_acl_entry)); ++ break; ++ default: ++ goto fail; ++ } ++ } ++ if ((char *)entry != end) ++ goto fail; ++ return acl; ++fail: ++ posix_acl_release(acl); ++ return ERR_PTR(-EINVAL); ++} ++ ++static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size) ++{ ++ struct f2fs_acl_header *f2fs_acl; ++ struct f2fs_acl_entry *entry; ++ int i; ++ ++ f2fs_acl = kmalloc(sizeof(struct f2fs_acl_header) + acl->a_count * ++ sizeof(struct f2fs_acl_entry), GFP_KERNEL); ++ if (!f2fs_acl) ++ return ERR_PTR(-ENOMEM); ++ ++ f2fs_acl->a_version = cpu_to_le32(F2FS_ACL_VERSION); ++ entry = (struct f2fs_acl_entry *)(f2fs_acl + 1); ++ ++ for (i = 0; i < acl->a_count; i++) { ++ ++ entry->e_tag = cpu_to_le16(acl->a_entries[i].e_tag); ++ entry->e_perm = cpu_to_le16(acl->a_entries[i].e_perm); ++ ++ switch (acl->a_entries[i].e_tag) { ++ case ACL_USER: ++ entry->e_id = cpu_to_le32( ++ from_kuid(&init_user_ns, ++ acl->a_entries[i].e_uid)); ++ entry = (struct f2fs_acl_entry *)((char *)entry + ++ sizeof(struct f2fs_acl_entry)); ++ break; ++ case ACL_GROUP: ++ entry->e_id = cpu_to_le32( ++ from_kgid(&init_user_ns, ++ acl->a_entries[i].e_gid)); ++ entry = (struct f2fs_acl_entry *)((char *)entry + ++ sizeof(struct f2fs_acl_entry)); ++ break; ++ case ACL_USER_OBJ: ++ case ACL_GROUP_OBJ: ++ case ACL_MASK: ++ case ACL_OTHER: ++ entry = (struct f2fs_acl_entry *)((char *)entry + ++ sizeof(struct f2fs_acl_entry_short)); ++ break; ++ default: ++ goto fail; ++ } ++ } ++ *size = f2fs_acl_size(acl->a_count); ++ return (void *)f2fs_acl; ++ ++fail: ++ kfree(f2fs_acl); ++ return ERR_PTR(-EINVAL); ++} ++ ++struct posix_acl *f2fs_get_acl(struct inode *inode, int type) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; ++ void *value = NULL; ++ struct posix_acl *acl; ++ int retval; ++ ++ if (!test_opt(sbi, POSIX_ACL)) ++ return NULL; ++ ++ acl = get_cached_acl(inode, type); ++ if (acl != ACL_NOT_CACHED) ++ return acl; ++ ++ if (type == ACL_TYPE_ACCESS) ++ name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; ++ ++ retval = f2fs_getxattr(inode, name_index, "", NULL, 0); ++ if (retval > 0) { ++ value = kmalloc(retval, GFP_KERNEL); ++ if (!value) ++ return ERR_PTR(-ENOMEM); ++ retval = f2fs_getxattr(inode, name_index, "", value, retval); ++ } ++ ++ if (retval < 0) { ++ if (retval == -ENODATA) ++ acl = NULL; ++ else ++ acl = ERR_PTR(retval); ++ } else { ++ acl = f2fs_acl_from_disk(value, retval); ++ } ++ kfree(value); ++ if (!IS_ERR(acl)) ++ set_cached_acl(inode, type, acl); ++ ++ return acl; ++} ++ ++static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct f2fs_inode_info *fi = F2FS_I(inode); ++ int name_index; ++ void *value = NULL; ++ size_t size = 0; ++ int error; ++ ++ if (!test_opt(sbi, POSIX_ACL)) ++ return 0; ++ if (S_ISLNK(inode->i_mode)) ++ return -EOPNOTSUPP; ++ ++ switch (type) { ++ case ACL_TYPE_ACCESS: ++ name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; ++ if (acl) { ++ error = posix_acl_equiv_mode(acl, &inode->i_mode); ++ if (error < 0) ++ return error; ++ set_acl_inode(fi, inode->i_mode); ++ if (error == 0) ++ acl = NULL; ++ } ++ break; ++ ++ case ACL_TYPE_DEFAULT: ++ name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; ++ if (!S_ISDIR(inode->i_mode)) ++ return acl ? -EACCES : 0; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ if (acl) { ++ value = f2fs_acl_to_disk(acl, &size); ++ if (IS_ERR(value)) { ++ cond_clear_inode_flag(fi, FI_ACL_MODE); ++ return (int)PTR_ERR(value); ++ } ++ } ++ ++ error = f2fs_setxattr(inode, name_index, "", value, size); ++ ++ kfree(value); ++ if (!error) ++ set_cached_acl(inode, type, acl); ++ ++ cond_clear_inode_flag(fi, FI_ACL_MODE); ++ return error; ++} ++ ++int f2fs_init_acl(struct inode *inode, struct inode *dir) ++{ ++ struct posix_acl *acl = NULL; ++ struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); ++ int error = 0; ++ ++ if (!S_ISLNK(inode->i_mode)) { ++ if (test_opt(sbi, POSIX_ACL)) { ++ acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT); ++ if (IS_ERR(acl)) ++ return PTR_ERR(acl); ++ } ++ if (!acl) ++ inode->i_mode &= ~current_umask(); ++ } ++ ++ if (test_opt(sbi, POSIX_ACL) && acl) { ++ ++ if (S_ISDIR(inode->i_mode)) { ++ error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl); ++ if (error) ++ goto cleanup; ++ } ++ error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); ++ if (error < 0) ++ return error; ++ if (error > 0) ++ error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl); ++ } ++cleanup: ++ posix_acl_release(acl); ++ return error; ++} ++ ++int f2fs_acl_chmod(struct inode *inode) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct posix_acl *acl; ++ int error; ++ mode_t mode = get_inode_mode(inode); ++ ++ if (!test_opt(sbi, POSIX_ACL)) ++ return 0; ++ if (S_ISLNK(mode)) ++ return -EOPNOTSUPP; ++ ++ acl = f2fs_get_acl(inode, ACL_TYPE_ACCESS); ++ if (IS_ERR(acl) || !acl) ++ return PTR_ERR(acl); ++ ++ error = posix_acl_chmod(&acl, GFP_KERNEL, mode); ++ if (error) ++ return error; ++ error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl); ++ posix_acl_release(acl); ++ return error; ++} ++ ++static size_t f2fs_xattr_list_acl(struct dentry *dentry, char *list, ++ size_t list_size, const char *name, size_t name_len, int type) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); ++ const char *xname = POSIX_ACL_XATTR_DEFAULT; ++ size_t size; ++ ++ if (!test_opt(sbi, POSIX_ACL)) ++ return 0; ++ ++ if (type == ACL_TYPE_ACCESS) ++ xname = POSIX_ACL_XATTR_ACCESS; ++ ++ size = strlen(xname) + 1; ++ if (list && size <= list_size) ++ memcpy(list, xname, size); ++ return size; ++} ++ ++static int f2fs_xattr_get_acl(struct dentry *dentry, const char *name, ++ void *buffer, size_t size, int type) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); ++ struct posix_acl *acl; ++ int error; ++ ++ if (strcmp(name, "") != 0) ++ return -EINVAL; ++ if (!test_opt(sbi, POSIX_ACL)) ++ return -EOPNOTSUPP; ++ ++ acl = f2fs_get_acl(dentry->d_inode, type); ++ if (IS_ERR(acl)) ++ return PTR_ERR(acl); ++ if (!acl) ++ return -ENODATA; ++ error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); ++ posix_acl_release(acl); ++ ++ return error; ++} ++ ++static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags, int type) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); ++ struct inode *inode = dentry->d_inode; ++ struct posix_acl *acl = NULL; ++ int error; ++ ++ if (strcmp(name, "") != 0) ++ return -EINVAL; ++ if (!test_opt(sbi, POSIX_ACL)) ++ return -EOPNOTSUPP; ++ if (!inode_owner_or_capable(inode)) ++ return -EPERM; ++ ++ if (value) { ++ acl = posix_acl_from_xattr(&init_user_ns, value, size); ++ if (IS_ERR(acl)) ++ return PTR_ERR(acl); ++ if (acl) { ++ error = posix_acl_valid(acl); ++ if (error) ++ goto release_and_out; ++ } ++ } else { ++ acl = NULL; ++ } ++ ++ error = f2fs_set_acl(inode, type, acl); ++ ++release_and_out: ++ posix_acl_release(acl); ++ return error; ++} ++ ++const struct xattr_handler f2fs_xattr_acl_default_handler = { ++ .prefix = POSIX_ACL_XATTR_DEFAULT, ++ .flags = ACL_TYPE_DEFAULT, ++ .list = f2fs_xattr_list_acl, ++ .get = f2fs_xattr_get_acl, ++ .set = f2fs_xattr_set_acl, ++}; ++ ++const struct xattr_handler f2fs_xattr_acl_access_handler = { ++ .prefix = POSIX_ACL_XATTR_ACCESS, ++ .flags = ACL_TYPE_ACCESS, ++ .list = f2fs_xattr_list_acl, ++ .get = f2fs_xattr_get_acl, ++ .set = f2fs_xattr_set_acl, ++}; ++ ++static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list, ++ size_t list_size, const char *name, size_t name_len, int type) ++{ ++ const char *xname = F2FS_SYSTEM_ADVISE_PREFIX; ++ size_t size; ++ ++ if (type != F2FS_XATTR_INDEX_ADVISE) ++ return 0; ++ ++ size = strlen(xname) + 1; ++ if (list && size <= list_size) ++ memcpy(list, xname, size); ++ return size; ++} ++ ++static int f2fs_xattr_advise_get(struct dentry *dentry, const char *name, ++ void *buffer, size_t size, int type) ++{ ++ struct inode *inode = dentry->d_inode; ++ ++ if (strcmp(name, "") != 0) ++ return -EINVAL; ++ ++ *((char *)buffer) = F2FS_I(inode)->i_advise; ++ return sizeof(char); ++} ++ ++static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags, int type) ++{ ++ struct inode *inode = dentry->d_inode; ++ ++ if (strcmp(name, "") != 0) ++ return -EINVAL; ++ if (!inode_owner_or_capable(inode)) ++ return -EPERM; ++ if (value == NULL) ++ return -EINVAL; ++ ++ F2FS_I(inode)->i_advise |= *(char *)value; ++ return 0; ++} ++ ++const struct xattr_handler f2fs_xattr_advise_handler = { ++ .prefix = F2FS_SYSTEM_ADVISE_PREFIX, ++ .flags = F2FS_XATTR_INDEX_ADVISE, ++ .list = f2fs_xattr_advise_list, ++ .get = f2fs_xattr_advise_get, ++ .set = f2fs_xattr_advise_set, ++}; +diff --git a/fs/f2fs/acl.h b/fs/f2fs/acl.h +new file mode 100644 +index 0000000..c97675e +--- /dev/null ++++ b/fs/f2fs/acl.h +@@ -0,0 +1,57 @@ ++/** ++ * fs/f2fs/acl.h ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * Portions of this code from linux/fs/ext2/acl.h ++ * ++ * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __F2FS_ACL_H__ ++#define __F2FS_ACL_H__ ++ ++#include <linux/posix_acl_xattr.h> ++ ++#define F2FS_ACL_VERSION 0x0001 ++ ++struct f2fs_acl_entry { ++ __le16 e_tag; ++ __le16 e_perm; ++ __le32 e_id; ++}; ++ ++struct f2fs_acl_entry_short { ++ __le16 e_tag; ++ __le16 e_perm; ++}; ++ ++struct f2fs_acl_header { ++ __le32 a_version; ++}; ++ ++#ifdef CONFIG_F2FS_FS_POSIX_ACL ++ ++extern struct posix_acl *f2fs_get_acl(struct inode *inode, int type); ++extern int f2fs_acl_chmod(struct inode *inode); ++extern int f2fs_init_acl(struct inode *inode, struct inode *dir); ++#else ++#define f2fs_check_acl NULL ++#define f2fs_get_acl NULL ++#define f2fs_set_acl NULL ++ ++static inline int f2fs_acl_chmod(struct inode *inode) ++{ ++ return 0; ++} ++ ++static inline int f2fs_init_acl(struct inode *inode, struct inode *dir) ++{ ++ return 0; ++} ++#endif ++#endif /* __F2FS_ACL_H__ */ +diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c +new file mode 100644 +index 0000000..aca50fe +--- /dev/null ++++ b/fs/f2fs/xattr.c +@@ -0,0 +1,389 @@ ++/** ++ * fs/f2fs/xattr.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * Portions of this code from linux/fs/ext2/xattr.c ++ * ++ * Copyright (C) 2001-2003 Andreas Gruenbacher <agruen@suse.de> ++ * ++ * Fix by Harrison Xing <harrison@mountainviewdata.com>. ++ * Extended attributes for symlinks and special files added per ++ * suggestion of Luka Renko <luka.renko@hermes.si>. ++ * xattr consolidation Copyright (c) 2004 James Morris <jmorris@redhat.com>, ++ * Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/rwsem.h> ++#include <linux/f2fs_fs.h> ++#include "f2fs.h" ++#include "xattr.h" ++ ++static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list, ++ size_t list_size, const char *name, size_t name_len, int type) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); ++ int total_len, prefix_len = 0; ++ const char *prefix = NULL; ++ ++ switch (type) { ++ case F2FS_XATTR_INDEX_USER: ++ if (!test_opt(sbi, XATTR_USER)) ++ return -EOPNOTSUPP; ++ prefix = XATTR_USER_PREFIX; ++ prefix_len = XATTR_USER_PREFIX_LEN; ++ break; ++ case F2FS_XATTR_INDEX_TRUSTED: ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ prefix = XATTR_TRUSTED_PREFIX; ++ prefix_len = XATTR_TRUSTED_PREFIX_LEN; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ total_len = prefix_len + name_len + 1; ++ if (list && total_len <= list_size) { ++ memcpy(list, prefix, prefix_len); ++ memcpy(list+prefix_len, name, name_len); ++ list[prefix_len + name_len] = '\0'; ++ } ++ return total_len; ++} ++ ++static int f2fs_xattr_generic_get(struct dentry *dentry, const char *name, ++ void *buffer, size_t size, int type) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); ++ ++ switch (type) { ++ case F2FS_XATTR_INDEX_USER: ++ if (!test_opt(sbi, XATTR_USER)) ++ return -EOPNOTSUPP; ++ break; ++ case F2FS_XATTR_INDEX_TRUSTED: ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ break; ++ default: ++ return -EINVAL; ++ } ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ return f2fs_getxattr(dentry->d_inode, type, name, ++ buffer, size); ++} ++ ++static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags, int type) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); ++ ++ switch (type) { ++ case F2FS_XATTR_INDEX_USER: ++ if (!test_opt(sbi, XATTR_USER)) ++ return -EOPNOTSUPP; ++ break; ++ case F2FS_XATTR_INDEX_TRUSTED: ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ break; ++ default: ++ return -EINVAL; ++ } ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ ++ return f2fs_setxattr(dentry->d_inode, type, name, value, size); ++} ++ ++const struct xattr_handler f2fs_xattr_user_handler = { ++ .prefix = XATTR_USER_PREFIX, ++ .flags = F2FS_XATTR_INDEX_USER, ++ .list = f2fs_xattr_generic_list, ++ .get = f2fs_xattr_generic_get, ++ .set = f2fs_xattr_generic_set, ++}; ++ ++const struct xattr_handler f2fs_xattr_trusted_handler = { ++ .prefix = XATTR_TRUSTED_PREFIX, ++ .flags = F2FS_XATTR_INDEX_TRUSTED, ++ .list = f2fs_xattr_generic_list, ++ .get = f2fs_xattr_generic_get, ++ .set = f2fs_xattr_generic_set, ++}; ++ ++static const struct xattr_handler *f2fs_xattr_handler_map[] = { ++ [F2FS_XATTR_INDEX_USER] = &f2fs_xattr_user_handler, ++#ifdef CONFIG_F2FS_FS_POSIX_ACL ++ [F2FS_XATTR_INDEX_POSIX_ACL_ACCESS] = &f2fs_xattr_acl_access_handler, ++ [F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &f2fs_xattr_acl_default_handler, ++#endif ++ [F2FS_XATTR_INDEX_TRUSTED] = &f2fs_xattr_trusted_handler, ++ [F2FS_XATTR_INDEX_ADVISE] = &f2fs_xattr_advise_handler, ++}; ++ ++const struct xattr_handler *f2fs_xattr_handlers[] = { ++ &f2fs_xattr_user_handler, ++#ifdef CONFIG_F2FS_FS_POSIX_ACL ++ &f2fs_xattr_acl_access_handler, ++ &f2fs_xattr_acl_default_handler, ++#endif ++ &f2fs_xattr_trusted_handler, ++ &f2fs_xattr_advise_handler, ++ NULL, ++}; ++ ++static inline const struct xattr_handler *f2fs_xattr_handler(int name_index) ++{ ++ const struct xattr_handler *handler = NULL; ++ ++ if (name_index > 0 && name_index < ARRAY_SIZE(f2fs_xattr_handler_map)) ++ handler = f2fs_xattr_handler_map[name_index]; ++ return handler; ++} ++ ++int f2fs_getxattr(struct inode *inode, int name_index, const char *name, ++ void *buffer, size_t buffer_size) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct f2fs_inode_info *fi = F2FS_I(inode); ++ struct f2fs_xattr_entry *entry; ++ struct page *page; ++ void *base_addr; ++ int error = 0, found = 0; ++ int value_len, name_len; ++ ++ if (name == NULL) ++ return -EINVAL; ++ name_len = strlen(name); ++ ++ if (!fi->i_xattr_nid) ++ return -ENODATA; ++ ++ page = get_node_page(sbi, fi->i_xattr_nid); ++ base_addr = page_address(page); ++ ++ list_for_each_xattr(entry, base_addr) { ++ if (entry->e_name_index != name_index) ++ continue; ++ if (entry->e_name_len != name_len) ++ continue; ++ if (!memcmp(entry->e_name, name, name_len)) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) { ++ error = -ENODATA; ++ goto cleanup; ++ } ++ ++ value_len = le16_to_cpu(entry->e_value_size); ++ ++ if (buffer && value_len > buffer_size) { ++ error = -ERANGE; ++ goto cleanup; ++ } ++ ++ if (buffer) { ++ char *pval = entry->e_name + entry->e_name_len; ++ memcpy(buffer, pval, value_len); ++ } ++ error = value_len; ++ ++cleanup: ++ f2fs_put_page(page, 1); ++ return error; ++} ++ ++ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) ++{ ++ struct inode *inode = dentry->d_inode; ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct f2fs_inode_info *fi = F2FS_I(inode); ++ struct f2fs_xattr_entry *entry; ++ struct page *page; ++ void *base_addr; ++ int error = 0; ++ size_t rest = buffer_size; ++ ++ if (!fi->i_xattr_nid) ++ return 0; ++ ++ page = get_node_page(sbi, fi->i_xattr_nid); ++ base_addr = page_address(page); ++ ++ list_for_each_xattr(entry, base_addr) { ++ const struct xattr_handler *handler = ++ f2fs_xattr_handler(entry->e_name_index); ++ size_t size; ++ ++ if (!handler) ++ continue; ++ ++ size = handler->list(dentry, buffer, rest, entry->e_name, ++ entry->e_name_len, handler->flags); ++ if (buffer && size > rest) { ++ error = -ERANGE; ++ goto cleanup; ++ } ++ ++ if (buffer) ++ buffer += size; ++ rest -= size; ++ } ++ error = buffer_size - rest; ++cleanup: ++ f2fs_put_page(page, 1); ++ return error; ++} ++ ++int f2fs_setxattr(struct inode *inode, int name_index, const char *name, ++ const void *value, size_t value_len) ++{ ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ struct f2fs_inode_info *fi = F2FS_I(inode); ++ struct f2fs_xattr_header *header = NULL; ++ struct f2fs_xattr_entry *here, *last; ++ struct page *page; ++ void *base_addr; ++ int error, found, free, name_len, newsize; ++ char *pval; ++ ++ if (name == NULL) ++ return -EINVAL; ++ name_len = strlen(name); ++ ++ if (value == NULL) ++ value_len = 0; ++ ++ if (name_len > 255 || value_len > MAX_VALUE_LEN) ++ return -ERANGE; ++ ++ mutex_lock_op(sbi, NODE_NEW); ++ if (!fi->i_xattr_nid) { ++ /* Allocate new attribute block */ ++ struct dnode_of_data dn; ++ ++ if (!alloc_nid(sbi, &fi->i_xattr_nid)) { ++ mutex_unlock_op(sbi, NODE_NEW); ++ return -ENOSPC; ++ } ++ set_new_dnode(&dn, inode, NULL, NULL, fi->i_xattr_nid); ++ mark_inode_dirty(inode); ++ ++ page = new_node_page(&dn, XATTR_NODE_OFFSET); ++ if (IS_ERR(page)) { ++ alloc_nid_failed(sbi, fi->i_xattr_nid); ++ fi->i_xattr_nid = 0; ++ mutex_unlock_op(sbi, NODE_NEW); ++ return PTR_ERR(page); ++ } ++ ++ alloc_nid_done(sbi, fi->i_xattr_nid); ++ base_addr = page_address(page); ++ header = XATTR_HDR(base_addr); ++ header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC); ++ header->h_refcount = cpu_to_le32(1); ++ } else { ++ /* The inode already has an extended attribute block. */ ++ page = get_node_page(sbi, fi->i_xattr_nid); ++ if (IS_ERR(page)) { ++ mutex_unlock_op(sbi, NODE_NEW); ++ return PTR_ERR(page); ++ } ++ ++ base_addr = page_address(page); ++ header = XATTR_HDR(base_addr); ++ } ++ ++ if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) { ++ error = -EIO; ++ goto cleanup; ++ } ++ ++ /* find entry with wanted name. */ ++ found = 0; ++ list_for_each_xattr(here, base_addr) { ++ if (here->e_name_index != name_index) ++ continue; ++ if (here->e_name_len != name_len) ++ continue; ++ if (!memcmp(here->e_name, name, name_len)) { ++ found = 1; ++ break; ++ } ++ } ++ ++ last = here; ++ ++ while (!IS_XATTR_LAST_ENTRY(last)) ++ last = XATTR_NEXT_ENTRY(last); ++ ++ newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + ++ name_len + value_len); ++ ++ /* 1. Check space */ ++ if (value) { ++ /* If value is NULL, it is remove operation. ++ * In case of update operation, we caculate free. ++ */ ++ free = MIN_OFFSET - ((char *)last - (char *)header); ++ if (found) ++ free = free - ENTRY_SIZE(here); ++ ++ if (free < newsize) { ++ error = -ENOSPC; ++ goto cleanup; ++ } ++ } ++ ++ /* 2. Remove old entry */ ++ if (found) { ++ /* If entry is found, remove old entry. ++ * If not found, remove operation is not needed. ++ */ ++ struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here); ++ int oldsize = ENTRY_SIZE(here); ++ ++ memmove(here, next, (char *)last - (char *)next); ++ last = (struct f2fs_xattr_entry *)((char *)last - oldsize); ++ memset(last, 0, oldsize); ++ } ++ ++ /* 3. Write new entry */ ++ if (value) { ++ /* Before we come here, old entry is removed. ++ * We just write new entry. */ ++ memset(last, 0, newsize); ++ last->e_name_index = name_index; ++ last->e_name_len = name_len; ++ memcpy(last->e_name, name, name_len); ++ pval = last->e_name + name_len; ++ memcpy(pval, value, value_len); ++ last->e_value_size = cpu_to_le16(value_len); ++ } ++ ++ set_page_dirty(page); ++ f2fs_put_page(page, 1); ++ ++ if (is_inode_flag_set(fi, FI_ACL_MODE)) { ++ inode->i_mode = fi->i_acl_mode; ++ inode->i_ctime = CURRENT_TIME; ++ clear_inode_flag(fi, FI_ACL_MODE); ++ } ++ f2fs_write_inode(inode, NULL); ++ mutex_unlock_op(sbi, NODE_NEW); ++ ++ return 0; ++cleanup: ++ f2fs_put_page(page, 1); ++ mutex_unlock_op(sbi, NODE_NEW); ++ return error; ++} +diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h +new file mode 100644 +index 0000000..29b0a08 +--- /dev/null ++++ b/fs/f2fs/xattr.h +@@ -0,0 +1,145 @@ ++/** ++ * fs/f2fs/xattr.h ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * Portions of this code from linux/fs/ext2/xattr.h ++ * ++ * On-disk format of extended attributes for the ext2 filesystem. ++ * ++ * (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __F2FS_XATTR_H__ ++#define __F2FS_XATTR_H__ ++ ++#include <linux/init.h> ++#include <linux/xattr.h> ++ ++/* Magic value in attribute blocks */ ++#define F2FS_XATTR_MAGIC 0xF2F52011 ++ ++/* Maximum number of references to one attribute block */ ++#define F2FS_XATTR_REFCOUNT_MAX 1024 ++ ++/* Name indexes */ ++#define F2FS_SYSTEM_ADVISE_PREFIX "system.advise" ++#define F2FS_XATTR_INDEX_USER 1 ++#define F2FS_XATTR_INDEX_POSIX_ACL_ACCESS 2 ++#define F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT 3 ++#define F2FS_XATTR_INDEX_TRUSTED 4 ++#define F2FS_XATTR_INDEX_LUSTRE 5 ++#define F2FS_XATTR_INDEX_SECURITY 6 ++#define F2FS_XATTR_INDEX_ADVISE 7 ++ ++struct f2fs_xattr_header { ++ __le32 h_magic; /* magic number for identification */ ++ __le32 h_refcount; /* reference count */ ++ __u32 h_reserved[4]; /* zero right now */ ++}; ++ ++struct f2fs_xattr_entry { ++ __u8 e_name_index; ++ __u8 e_name_len; ++ __le16 e_value_size; /* size of attribute value */ ++ char e_name[0]; /* attribute name */ ++}; ++ ++#define XATTR_HDR(ptr) ((struct f2fs_xattr_header *)(ptr)) ++#define XATTR_ENTRY(ptr) ((struct f2fs_xattr_entry *)(ptr)) ++#define XATTR_FIRST_ENTRY(ptr) (XATTR_ENTRY(XATTR_HDR(ptr)+1)) ++#define XATTR_ROUND (3) ++ ++#define XATTR_ALIGN(size) ((size + XATTR_ROUND) & ~XATTR_ROUND) ++ ++#define ENTRY_SIZE(entry) (XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + \ ++ entry->e_name_len + le16_to_cpu(entry->e_value_size))) ++ ++#define XATTR_NEXT_ENTRY(entry) ((struct f2fs_xattr_entry *)((char *)(entry) +\ ++ ENTRY_SIZE(entry))) ++ ++#define IS_XATTR_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) ++ ++#define list_for_each_xattr(entry, addr) \ ++ for (entry = XATTR_FIRST_ENTRY(addr);\ ++ !IS_XATTR_LAST_ENTRY(entry);\ ++ entry = XATTR_NEXT_ENTRY(entry)) ++ ++ ++#define MIN_OFFSET XATTR_ALIGN(PAGE_SIZE - \ ++ sizeof(struct node_footer) - \ ++ sizeof(__u32)) ++ ++#define MAX_VALUE_LEN (MIN_OFFSET - sizeof(struct f2fs_xattr_header) - \ ++ sizeof(struct f2fs_xattr_entry)) ++ ++/** ++ * On-disk structure of f2fs_xattr ++ * We use only 1 block for xattr. ++ * ++ * +--------------------+ ++ * | f2fs_xattr_header | ++ * | | ++ * +--------------------+ ++ * | f2fs_xattr_entry | ++ * | .e_name_index = 1 | ++ * | .e_name_len = 3 | ++ * | .e_value_size = 14 | ++ * | .e_name = "foo" | ++ * | "value_of_xattr" |<- value_offs = e_name + e_name_len ++ * +--------------------+ ++ * | f2fs_xattr_entry | ++ * | .e_name_index = 4 | ++ * | .e_name = "bar" | ++ * +--------------------+ ++ * | | ++ * | Free | ++ * | | ++ * +--------------------+<- MIN_OFFSET ++ * | node_footer | ++ * | (nid, ino, offset) | ++ * +--------------------+ ++ * ++ **/ ++ ++#ifdef CONFIG_F2FS_FS_XATTR ++extern const struct xattr_handler f2fs_xattr_user_handler; ++extern const struct xattr_handler f2fs_xattr_trusted_handler; ++extern const struct xattr_handler f2fs_xattr_acl_access_handler; ++extern const struct xattr_handler f2fs_xattr_acl_default_handler; ++extern const struct xattr_handler f2fs_xattr_advise_handler; ++ ++extern const struct xattr_handler *f2fs_xattr_handlers[]; ++ ++extern int f2fs_setxattr(struct inode *inode, int name_index, const char *name, ++ const void *value, size_t value_len); ++extern int f2fs_getxattr(struct inode *inode, int name_index, const char *name, ++ void *buffer, size_t buffer_size); ++extern ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, ++ size_t buffer_size); ++ ++#else ++ ++#define f2fs_xattr_handlers NULL ++static inline int f2fs_setxattr(struct inode *inode, int name_index, ++ const char *name, const void *value, size_t value_len) ++{ ++ return -EOPNOTSUPP; ++} ++static inline int f2fs_getxattr(struct inode *inode, int name_index, ++ const char *name, void *buffer, size_t buffer_size) ++{ ++ return -EOPNOTSUPP; ++} ++static inline ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, ++ size_t buffer_size) ++{ ++ return -EOPNOTSUPP; ++} ++#endif ++ ++#endif /* __F2FS_XATTR_H__ */ diff --git a/patches/linux-3.7-rc6/0111-f2fs-add-garbage-collection-functions.patch b/patches/linux-3.7-rc6/0111-f2fs-add-garbage-collection-functions.patch new file mode 100644 index 0000000..ef99275 --- /dev/null +++ b/patches/linux-3.7-rc6/0111-f2fs-add-garbage-collection-functions.patch @@ -0,0 +1,1395 @@ +From 441b0d2cd8b763ad0f4b5e6294c354e5ac4beee2 Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:32:20 +0000 +Subject: [PATCH] f2fs: add garbage collection functions + +This adds on-demand and background cleaning functions. + +- The basic background cleaning policy is trying to do cleaning jobs as much as + possible whenever the system is idle. Once the background cleaning is done, + the cleaner sleeps an amount of time not to interfere with VFS calls. The time + is dynamically adjusted according to the status of whole segments, which is + decreased when the following conditions are satisfied. + + . GC is not conducted currently, and + . IO subsystem is idle by checking the number of requets in bdev's request + list, and + . There are enough dirty segments. + + Otherwise, the time is increased incrementally until to the maximum time. + Note that, min and max times are 10 secs and 30 secs by default. + +- F2FS adopts a default victim selection policy where background cleaning uses + a cost-benefit algorithm, while on-demand cleaning uses a greedy algorithm. + +- The method of moving data during the cleaning is slightly different between + background and on-demand cleaning schemes. In the case of background cleaning, + F2FS loads the data, and marks them as dirty. Then, F2FS expects that the data + will be moved by flusher or VM. In the case of on-demand cleaning, F2FS should + move the data right away. + +- In order to identify valid blocks in a victim segment, F2FS scans the bitmap + of the segment managed as an SIT entry. + +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/f2fs/gc.c | 1139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/f2fs/gc.h | 203 +++++++++++ + 2 files changed, 1342 insertions(+) + create mode 100644 fs/f2fs/gc.c + create mode 100644 fs/f2fs/gc.h + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +new file mode 100644 +index 0000000..753b05e +--- /dev/null ++++ b/fs/f2fs/gc.c +@@ -0,0 +1,1139 @@ ++/** ++ * fs/f2fs/gc.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/fs.h> ++#include <linux/module.h> ++#include <linux/backing-dev.h> ++#include <linux/proc_fs.h> ++#include <linux/init.h> ++#include <linux/f2fs_fs.h> ++#include <linux/kthread.h> ++#include <linux/delay.h> ++#include <linux/freezer.h> ++#include <linux/blkdev.h> ++ ++#include "f2fs.h" ++#include "node.h" ++#include "segment.h" ++#include "gc.h" ++ ++static LIST_HEAD(f2fs_stat_list); ++static struct kmem_cache *winode_slab; ++ ++static int gc_thread_func(void *data) ++{ ++ struct f2fs_sb_info *sbi = data; ++ wait_queue_head_t *wq = &sbi->gc_thread->gc_wait_queue_head; ++ long wait_ms; ++ ++ wait_ms = GC_THREAD_MIN_SLEEP_TIME; ++ ++ do { ++ if (try_to_freeze()) ++ continue; ++ else ++ wait_event_interruptible_timeout(*wq, ++ kthread_should_stop(), ++ msecs_to_jiffies(wait_ms)); ++ if (kthread_should_stop()) ++ break; ++ ++ f2fs_balance_fs(sbi); ++ ++ if (!test_opt(sbi, BG_GC)) ++ continue; ++ ++ /* ++ * [GC triggering condition] ++ * 0. GC is not conducted currently. ++ * 1. There are enough dirty segments. ++ * 2. IO subsystem is idle by checking the # of writeback pages. ++ * 3. IO subsystem is idle by checking the # of requests in ++ * bdev's request list. ++ * ++ * Note) We have to avoid triggering GCs too much frequently. ++ * Because it is possible that some segments can be ++ * invalidated soon after by user update or deletion. ++ * So, I'd like to wait some time to collect dirty segments. ++ */ ++ if (!mutex_trylock(&sbi->gc_mutex)) ++ continue; ++ ++ if (!is_idle(sbi)) { ++ wait_ms = increase_sleep_time(wait_ms); ++ mutex_unlock(&sbi->gc_mutex); ++ continue; ++ } ++ ++ if (has_enough_invalid_blocks(sbi)) ++ wait_ms = decrease_sleep_time(wait_ms); ++ else ++ wait_ms = increase_sleep_time(wait_ms); ++ ++ sbi->bg_gc++; ++ ++ if (f2fs_gc(sbi, 1) == GC_NONE) ++ wait_ms = GC_THREAD_NOGC_SLEEP_TIME; ++ else if (wait_ms == GC_THREAD_NOGC_SLEEP_TIME) ++ wait_ms = GC_THREAD_MAX_SLEEP_TIME; ++ ++ } while (!kthread_should_stop()); ++ return 0; ++} ++ ++int start_gc_thread(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_gc_kthread *gc_th = NULL; ++ ++ gc_th = kmalloc(sizeof(struct f2fs_gc_kthread), GFP_KERNEL); ++ if (!gc_th) ++ return -ENOMEM; ++ ++ sbi->gc_thread = gc_th; ++ init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head); ++ sbi->gc_thread->f2fs_gc_task = kthread_run(gc_thread_func, sbi, ++ GC_THREAD_NAME); ++ if (IS_ERR(gc_th->f2fs_gc_task)) { ++ kfree(gc_th); ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++void stop_gc_thread(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_gc_kthread *gc_th = sbi->gc_thread; ++ if (!gc_th) ++ return; ++ kthread_stop(gc_th->f2fs_gc_task); ++ kfree(gc_th); ++ sbi->gc_thread = NULL; ++} ++ ++static int select_gc_type(int gc_type) ++{ ++ return (gc_type == BG_GC) ? GC_CB : GC_GREEDY; ++} ++ ++static void select_policy(struct f2fs_sb_info *sbi, int gc_type, ++ int type, struct victim_sel_policy *p) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ ++ if (IS_SSR_TYPE(type)) { ++ p->alloc_mode = SSR; ++ p->gc_mode = GC_GREEDY; ++ p->type = GET_SSR_TYPE(type); ++ p->dirty_segmap = dirty_i->dirty_segmap[p->type]; ++ p->ofs_unit = 1; ++ } else { ++ p->alloc_mode = LFS; ++ p->gc_mode = select_gc_type(gc_type); ++ p->type = 0; ++ p->dirty_segmap = dirty_i->dirty_segmap[DIRTY]; ++ p->ofs_unit = sbi->segs_per_sec; ++ } ++ p->offset = sbi->last_victim[p->gc_mode]; ++} ++ ++static unsigned int get_max_cost(struct f2fs_sb_info *sbi, ++ struct victim_sel_policy *p) ++{ ++ if (p->gc_mode == GC_GREEDY) ++ return (1 << sbi->log_blocks_per_seg) * p->ofs_unit; ++ else if (p->gc_mode == GC_CB) ++ return UINT_MAX; ++ else /* No other gc_mode */ ++ return 0; ++} ++ ++static unsigned int check_bg_victims(struct f2fs_sb_info *sbi) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ unsigned int segno; ++ ++ /* ++ * If the gc_type is FG_GC, we can select victim segments ++ * selected by background GC before. ++ * Those segments guarantee they have small valid blocks. ++ */ ++ segno = find_next_bit(dirty_i->victim_segmap[BG_GC], ++ TOTAL_SEGS(sbi), 0); ++ if (segno < TOTAL_SEGS(sbi)) { ++ clear_bit(segno, dirty_i->victim_segmap[BG_GC]); ++ return segno; ++ } ++ return NULL_SEGNO; ++} ++ ++static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ unsigned int secno = GET_SECNO(sbi, segno); ++ unsigned int start = secno * sbi->segs_per_sec; ++ unsigned long long mtime = 0; ++ unsigned int vblocks; ++ unsigned char age = 0; ++ unsigned char u; ++ unsigned int i; ++ ++ for (i = 0; i < sbi->segs_per_sec; i++) ++ mtime += get_seg_entry(sbi, start + i)->mtime; ++ vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec); ++ ++ mtime = div_u64(mtime, sbi->segs_per_sec); ++ vblocks = div_u64(vblocks, sbi->segs_per_sec); ++ ++ u = (vblocks * 100) >> sbi->log_blocks_per_seg; ++ ++ /* Handle if the system time is changed by user */ ++ if (mtime < sit_i->min_mtime) ++ sit_i->min_mtime = mtime; ++ if (mtime > sit_i->max_mtime) ++ sit_i->max_mtime = mtime; ++ if (sit_i->max_mtime != sit_i->min_mtime) ++ age = 100 - div64_u64(100 * (mtime - sit_i->min_mtime), ++ sit_i->max_mtime - sit_i->min_mtime); ++ ++ return UINT_MAX - ((100 * (100 - u) * age) / (100 + u)); ++} ++ ++static unsigned int get_gc_cost(struct f2fs_sb_info *sbi, unsigned int segno, ++ struct victim_sel_policy *p) ++{ ++ if (p->alloc_mode == SSR) ++ return get_seg_entry(sbi, segno)->ckpt_valid_blocks; ++ ++ /* alloc_mode == LFS */ ++ if (p->gc_mode == GC_GREEDY) ++ return get_valid_blocks(sbi, segno, sbi->segs_per_sec); ++ else ++ return get_cb_cost(sbi, segno); ++} ++ ++/** ++ * This function is called from two pathes. ++ * One is garbage collection and the other is SSR segment selection. ++ * When it is called during GC, it just gets a victim segment ++ * and it does not remove it from dirty seglist. ++ * When it is called from SSR segment selection, it finds a segment ++ * which has minimum valid blocks and removes it from dirty seglist. ++ */ ++static int get_victim_by_default(struct f2fs_sb_info *sbi, ++ unsigned int *result, int gc_type, int type) ++{ ++ struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); ++ struct victim_sel_policy p; ++ unsigned int segno; ++ int nsearched = 0; ++ ++ select_policy(sbi, gc_type, type, &p); ++ ++ p.min_segno = NULL_SEGNO; ++ p.min_cost = get_max_cost(sbi, &p); ++ ++ mutex_lock(&dirty_i->seglist_lock); ++ ++ if (p.alloc_mode == LFS && gc_type == FG_GC) { ++ p.min_segno = check_bg_victims(sbi); ++ if (p.min_segno != NULL_SEGNO) ++ goto got_it; ++ } ++ ++ while (1) { ++ unsigned long cost; ++ ++ segno = find_next_bit(p.dirty_segmap, ++ TOTAL_SEGS(sbi), p.offset); ++ if (segno >= TOTAL_SEGS(sbi)) { ++ if (sbi->last_victim[p.gc_mode]) { ++ sbi->last_victim[p.gc_mode] = 0; ++ p.offset = 0; ++ continue; ++ } ++ break; ++ } ++ p.offset = ((segno / p.ofs_unit) * p.ofs_unit) + p.ofs_unit; ++ ++ if (test_bit(segno, dirty_i->victim_segmap[FG_GC])) ++ continue; ++ if (gc_type == BG_GC && ++ test_bit(segno, dirty_i->victim_segmap[BG_GC])) ++ continue; ++ if (IS_CURSEC(sbi, GET_SECNO(sbi, segno))) ++ continue; ++ ++ cost = get_gc_cost(sbi, segno, &p); ++ ++ if (p.min_cost > cost) { ++ p.min_segno = segno; ++ p.min_cost = cost; ++ } ++ ++ if (cost == get_max_cost(sbi, &p)) ++ continue; ++ ++ if (nsearched++ >= MAX_VICTIM_SEARCH) { ++ sbi->last_victim[p.gc_mode] = segno; ++ break; ++ } ++ } ++got_it: ++ if (p.min_segno != NULL_SEGNO) { ++ *result = (p.min_segno / p.ofs_unit) * p.ofs_unit; ++ if (p.alloc_mode == LFS) { ++ int i; ++ for (i = 0; i < p.ofs_unit; i++) ++ set_bit(*result + i, ++ dirty_i->victim_segmap[gc_type]); ++ } ++ } ++ mutex_unlock(&dirty_i->seglist_lock); ++ ++ return (p.min_segno == NULL_SEGNO) ? 0 : 1; ++} ++ ++static const struct victim_selection default_v_ops = { ++ .get_victim = get_victim_by_default, ++}; ++ ++static struct inode *find_gc_inode(nid_t ino, struct list_head *ilist) ++{ ++ struct list_head *this; ++ struct inode_entry *ie; ++ ++ list_for_each(this, ilist) { ++ ie = list_entry(this, struct inode_entry, list); ++ if (ie->inode->i_ino == ino) ++ return ie->inode; ++ } ++ return NULL; ++} ++ ++static void add_gc_inode(struct inode *inode, struct list_head *ilist) ++{ ++ struct list_head *this; ++ struct inode_entry *new_ie, *ie; ++ ++ list_for_each(this, ilist) { ++ ie = list_entry(this, struct inode_entry, list); ++ if (ie->inode == inode) { ++ iput(inode); ++ return; ++ } ++ } ++repeat: ++ new_ie = kmem_cache_alloc(winode_slab, GFP_NOFS); ++ if (!new_ie) { ++ cond_resched(); ++ goto repeat; ++ } ++ new_ie->inode = inode; ++ list_add_tail(&new_ie->list, ilist); ++} ++ ++static void put_gc_inode(struct list_head *ilist) ++{ ++ struct inode_entry *ie, *next_ie; ++ list_for_each_entry_safe(ie, next_ie, ilist, list) { ++ iput(ie->inode); ++ list_del(&ie->list); ++ kmem_cache_free(winode_slab, ie); ++ } ++} ++ ++static int check_valid_map(struct f2fs_sb_info *sbi, ++ unsigned int segno, int offset) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ struct seg_entry *sentry; ++ int ret; ++ ++ mutex_lock(&sit_i->sentry_lock); ++ sentry = get_seg_entry(sbi, segno); ++ ret = f2fs_test_bit(offset, sentry->cur_valid_map); ++ mutex_unlock(&sit_i->sentry_lock); ++ return ret ? GC_OK : GC_NEXT; ++} ++ ++/** ++ * This function compares node address got in summary with that in NAT. ++ * On validity, copy that node with cold status, otherwise (invalid node) ++ * ignore that. ++ */ ++static int gc_node_segment(struct f2fs_sb_info *sbi, ++ struct f2fs_summary *sum, unsigned int segno, int gc_type) ++{ ++ bool initial = true; ++ struct f2fs_summary *entry; ++ int off; ++ ++next_step: ++ entry = sum; ++ for (off = 0; off < sbi->blocks_per_seg; off++, entry++) { ++ nid_t nid = le32_to_cpu(entry->nid); ++ struct page *node_page; ++ int err; ++ ++ /* ++ * It makes sure that free segments are able to write ++ * all the dirty node pages before CP after this CP. ++ * So let's check the space of dirty node pages. ++ */ ++ if (should_do_checkpoint(sbi)) { ++ mutex_lock(&sbi->cp_mutex); ++ block_operations(sbi); ++ return GC_BLOCKED; ++ } ++ ++ err = check_valid_map(sbi, segno, off); ++ if (err == GC_ERROR) ++ return err; ++ else if (err == GC_NEXT) ++ continue; ++ ++ if (initial) { ++ ra_node_page(sbi, nid); ++ continue; ++ } ++ node_page = get_node_page(sbi, nid); ++ if (IS_ERR(node_page)) ++ continue; ++ ++ /* set page dirty and write it */ ++ if (!PageWriteback(node_page)) ++ set_page_dirty(node_page); ++ f2fs_put_page(node_page, 1); ++ gc_stat_inc_node_blk_count(sbi, 1); ++ } ++ if (initial) { ++ initial = false; ++ goto next_step; ++ } ++ ++ if (gc_type == FG_GC) { ++ struct writeback_control wbc = { ++ .sync_mode = WB_SYNC_ALL, ++ .nr_to_write = LONG_MAX, ++ .for_reclaim = 0, ++ }; ++ sync_node_pages(sbi, 0, &wbc); ++ } ++ return GC_DONE; ++} ++ ++/** ++ * Calculate start block index that this node page contains ++ */ ++block_t start_bidx_of_node(unsigned int node_ofs) ++{ ++ block_t start_bidx; ++ unsigned int bidx, indirect_blks; ++ int dec; ++ ++ indirect_blks = 2 * NIDS_PER_BLOCK + 4; ++ ++ start_bidx = 1; ++ if (node_ofs == 0) { ++ start_bidx = 0; ++ } else if (node_ofs <= 2) { ++ bidx = node_ofs - 1; ++ } else if (node_ofs <= indirect_blks) { ++ dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1); ++ bidx = node_ofs - 2 - dec; ++ } else { ++ dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1); ++ bidx = node_ofs - 5 - dec; ++ } ++ ++ if (start_bidx) ++ start_bidx = bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE; ++ return start_bidx; ++} ++ ++static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, ++ struct node_info *dni, block_t blkaddr, unsigned int *nofs) ++{ ++ struct page *node_page; ++ nid_t nid; ++ unsigned int ofs_in_node; ++ block_t source_blkaddr; ++ ++ nid = le32_to_cpu(sum->nid); ++ ofs_in_node = le16_to_cpu(sum->ofs_in_node); ++ ++ node_page = get_node_page(sbi, nid); ++ if (IS_ERR(node_page)) ++ return GC_NEXT; ++ ++ get_node_info(sbi, nid, dni); ++ ++ if (sum->version != dni->version) { ++ f2fs_put_page(node_page, 1); ++ return GC_NEXT; ++ } ++ ++ *nofs = ofs_of_node(node_page); ++ source_blkaddr = datablock_addr(node_page, ofs_in_node); ++ f2fs_put_page(node_page, 1); ++ ++ if (source_blkaddr != blkaddr) ++ return GC_NEXT; ++ return GC_OK; ++} ++ ++static void move_data_page(struct inode *inode, struct page *page, int gc_type) ++{ ++ if (page->mapping != inode->i_mapping) ++ goto out; ++ ++ if (inode != page->mapping->host) ++ goto out; ++ ++ if (PageWriteback(page)) ++ goto out; ++ ++ if (gc_type == BG_GC) { ++ set_page_dirty(page); ++ set_cold_data(page); ++ } else { ++ struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); ++ mutex_lock_op(sbi, DATA_WRITE); ++ if (clear_page_dirty_for_io(page) && ++ S_ISDIR(inode->i_mode)) { ++ dec_page_count(sbi, F2FS_DIRTY_DENTS); ++ inode_dec_dirty_dents(inode); ++ } ++ set_cold_data(page); ++ do_write_data_page(page); ++ mutex_unlock_op(sbi, DATA_WRITE); ++ clear_cold_data(page); ++ } ++out: ++ f2fs_put_page(page, 1); ++} ++ ++/** ++ * This function tries to get parent node of victim data block, and identifies ++ * data block validity. If the block is valid, copy that with cold status and ++ * modify parent node. ++ * If the parent node is not valid or the data block address is different, ++ * the victim data block is ignored. ++ */ ++static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, ++ struct list_head *ilist, unsigned int segno, int gc_type) ++{ ++ struct super_block *sb = sbi->sb; ++ struct f2fs_summary *entry; ++ block_t start_addr; ++ int err, off; ++ int phase = 0; ++ ++ start_addr = START_BLOCK(sbi, segno); ++ ++next_step: ++ entry = sum; ++ for (off = 0; off < sbi->blocks_per_seg; off++, entry++) { ++ struct page *data_page; ++ struct inode *inode; ++ struct node_info dni; /* dnode info for the data */ ++ unsigned int ofs_in_node, nofs; ++ block_t start_bidx; ++ ++ /* ++ * It makes sure that free segments are able to write ++ * all the dirty node pages before CP after this CP. ++ * So let's check the space of dirty node pages. ++ */ ++ if (should_do_checkpoint(sbi)) { ++ mutex_lock(&sbi->cp_mutex); ++ block_operations(sbi); ++ err = GC_BLOCKED; ++ goto stop; ++ } ++ ++ err = check_valid_map(sbi, segno, off); ++ if (err == GC_ERROR) ++ goto stop; ++ else if (err == GC_NEXT) ++ continue; ++ ++ if (phase == 0) { ++ ra_node_page(sbi, le32_to_cpu(entry->nid)); ++ continue; ++ } ++ ++ /* Get an inode by ino with checking validity */ ++ err = check_dnode(sbi, entry, &dni, start_addr + off, &nofs); ++ if (err == GC_ERROR) ++ goto stop; ++ else if (err == GC_NEXT) ++ continue; ++ ++ if (phase == 1) { ++ ra_node_page(sbi, dni.ino); ++ continue; ++ } ++ ++ start_bidx = start_bidx_of_node(nofs); ++ ofs_in_node = le16_to_cpu(entry->ofs_in_node); ++ ++ if (phase == 2) { ++ inode = f2fs_iget_nowait(sb, dni.ino); ++ if (IS_ERR(inode)) ++ continue; ++ ++ data_page = find_data_page(inode, ++ start_bidx + ofs_in_node); ++ if (IS_ERR(data_page)) ++ goto next_iput; ++ ++ f2fs_put_page(data_page, 0); ++ add_gc_inode(inode, ilist); ++ } else { ++ inode = find_gc_inode(dni.ino, ilist); ++ if (inode) { ++ data_page = get_lock_data_page(inode, ++ start_bidx + ofs_in_node); ++ if (IS_ERR(data_page)) ++ continue; ++ move_data_page(inode, data_page, gc_type); ++ gc_stat_inc_data_blk_count(sbi, 1); ++ } ++ } ++ continue; ++next_iput: ++ iput(inode); ++ } ++ if (++phase < 4) ++ goto next_step; ++ err = GC_DONE; ++stop: ++ if (gc_type == FG_GC) ++ f2fs_submit_bio(sbi, DATA, true); ++ return err; ++} ++ ++static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *result, ++ int gc_type, int type) ++{ ++ struct sit_info *sit_i = SIT_I(sbi); ++ int ret; ++ mutex_lock(&sit_i->sentry_lock); ++ ret = DIRTY_I(sbi)->v_ops->get_victim(sbi, result, gc_type, type); ++ mutex_unlock(&sit_i->sentry_lock); ++ return ret; ++} ++ ++static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno, ++ struct list_head *ilist, int gc_type) ++{ ++ struct page *sum_page; ++ struct f2fs_summary_block *sum; ++ int ret = GC_DONE; ++ ++ /* read segment summary of victim */ ++ sum_page = get_sum_page(sbi, segno); ++ if (IS_ERR(sum_page)) ++ return GC_ERROR; ++ ++ /* ++ * CP needs to lock sum_page. In this time, we don't need ++ * to lock this page, because this summary page is not gone anywhere. ++ * Also, this page is not gonna be updated before GC is done. ++ */ ++ unlock_page(sum_page); ++ sum = page_address(sum_page); ++ ++ switch (GET_SUM_TYPE((&sum->footer))) { ++ case SUM_TYPE_NODE: ++ ret = gc_node_segment(sbi, sum->entries, segno, gc_type); ++ break; ++ case SUM_TYPE_DATA: ++ ret = gc_data_segment(sbi, sum->entries, ilist, segno, gc_type); ++ break; ++ } ++ gc_stat_inc_seg_count(sbi, GET_SUM_TYPE((&sum->footer))); ++ gc_stat_inc_call_count(sbi->gc_info); ++ ++ f2fs_put_page(sum_page, 0); ++ return ret; ++} ++ ++int f2fs_gc(struct f2fs_sb_info *sbi, int nGC) ++{ ++ unsigned int segno; ++ int old_free_secs, cur_free_secs; ++ int gc_status, nfree; ++ struct list_head ilist; ++ int gc_type = BG_GC; ++ ++ INIT_LIST_HEAD(&ilist); ++gc_more: ++ nfree = 0; ++ gc_status = GC_NONE; ++ ++ if (has_not_enough_free_secs(sbi)) ++ old_free_secs = reserved_sections(sbi); ++ else ++ old_free_secs = free_sections(sbi); ++ ++ while (sbi->sb->s_flags & MS_ACTIVE) { ++ int i; ++ if (has_not_enough_free_secs(sbi)) ++ gc_type = FG_GC; ++ ++ cur_free_secs = free_sections(sbi) + nfree; ++ ++ /* We got free space successfully. */ ++ if (nGC < cur_free_secs - old_free_secs) ++ break; ++ ++ if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE)) ++ break; ++ ++ for (i = 0; i < sbi->segs_per_sec; i++) { ++ /* ++ * do_garbage_collect will give us three gc_status: ++ * GC_ERROR, GC_DONE, and GC_BLOCKED. ++ * If GC is finished uncleanly, we have to return ++ * the victim to dirty segment list. ++ */ ++ gc_status = do_garbage_collect(sbi, segno + i, ++ &ilist, gc_type); ++ if (gc_status != GC_DONE) ++ goto stop; ++ nfree++; ++ } ++ } ++stop: ++ if (has_not_enough_free_secs(sbi) || gc_status == GC_BLOCKED) { ++ write_checkpoint(sbi, (gc_status == GC_BLOCKED), false); ++ if (nfree) ++ goto gc_more; ++ } ++ sbi->last_gc_status = gc_status; ++ mutex_unlock(&sbi->gc_mutex); ++ ++ put_gc_inode(&ilist); ++ BUG_ON(!list_empty(&ilist)); ++ return gc_status; ++} ++ ++#ifdef CONFIG_F2FS_STAT_FS ++void f2fs_update_stat(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_gc_info *gc_i = sbi->gc_info; ++ struct f2fs_stat_info *si = gc_i->stat_info; ++ int i; ++ ++ /* valid check of the segment numbers */ ++ si->hit_ext = sbi->read_hit_ext; ++ si->total_ext = sbi->total_hit_ext; ++ si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES); ++ si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS); ++ si->ndirty_dirs = sbi->n_dirty_dirs; ++ si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META); ++ si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg; ++ si->rsvd_segs = reserved_segments(sbi); ++ si->overp_segs = overprovision_segments(sbi); ++ si->valid_count = valid_user_blocks(sbi); ++ si->valid_node_count = valid_node_count(sbi); ++ si->valid_inode_count = valid_inode_count(sbi); ++ si->utilization = utilization(sbi); ++ ++ si->free_segs = free_segments(sbi); ++ si->free_secs = free_sections(sbi); ++ si->prefree_count = prefree_segments(sbi); ++ si->dirty_count = dirty_segments(sbi); ++ si->node_pages = sbi->node_inode->i_mapping->nrpages; ++ si->meta_pages = sbi->meta_inode->i_mapping->nrpages; ++ si->nats = NM_I(sbi)->nat_cnt; ++ si->sits = SIT_I(sbi)->dirty_sentries; ++ si->fnids = NM_I(sbi)->fcnt; ++ si->bg_gc = sbi->bg_gc; ++ si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg) ++ * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg) ++ / 2; ++ si->util_valid = (int)(written_block_count(sbi) >> ++ sbi->log_blocks_per_seg) ++ * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg) ++ / 2; ++ si->util_invalid = 50 - si->util_free - si->util_valid; ++ for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_NODE; i++) { ++ struct curseg_info *curseg = CURSEG_I(sbi, i); ++ si->curseg[i] = curseg->segno; ++ si->cursec[i] = curseg->segno / sbi->segs_per_sec; ++ si->curzone[i] = si->cursec[i] / sbi->secs_per_zone; ++ } ++ ++ for (i = 0; i < 2; i++) { ++ si->segment_count[i] = sbi->segment_count[i]; ++ si->block_count[i] = sbi->block_count[i]; ++ } ++} ++ ++/** ++ * This function calculates BDF of every segments ++ */ ++void f2fs_update_gc_metric(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_gc_info *gc_i = sbi->gc_info; ++ struct f2fs_stat_info *si = gc_i->stat_info; ++ unsigned int blks_per_sec, hblks_per_sec, total_vblocks, bimodal, dist; ++ struct sit_info *sit_i = SIT_I(sbi); ++ unsigned int segno, vblocks; ++ int ndirty = 0; ++ ++ bimodal = 0; ++ total_vblocks = 0; ++ blks_per_sec = sbi->segs_per_sec * (1 << sbi->log_blocks_per_seg); ++ hblks_per_sec = blks_per_sec / 2; ++ mutex_lock(&sit_i->sentry_lock); ++ for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) { ++ vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec); ++ dist = abs(vblocks - hblks_per_sec); ++ bimodal += dist * dist; ++ ++ if (vblocks > 0 && vblocks < blks_per_sec) { ++ total_vblocks += vblocks; ++ ndirty++; ++ } ++ } ++ mutex_unlock(&sit_i->sentry_lock); ++ dist = sbi->total_sections * hblks_per_sec * hblks_per_sec / 100; ++ si->bimodal = bimodal / dist; ++ if (si->dirty_count) ++ si->avg_vblocks = total_vblocks / ndirty; ++ else ++ si->avg_vblocks = 0; ++} ++ ++static int f2fs_read_gc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct f2fs_gc_info *gc_i, *next; ++ struct f2fs_stat_info *si; ++ char *buf = page; ++ int i = 0; ++ ++ list_for_each_entry_safe(gc_i, next, &f2fs_stat_list, stat_list) { ++ int j; ++ si = gc_i->stat_info; ++ ++ mutex_lock(&si->stat_list); ++ if (!si->sbi) { ++ mutex_unlock(&si->stat_list); ++ continue; ++ } ++ f2fs_update_stat(si->sbi); ++ ++ buf += sprintf(buf, "=====[ partition info. #%d ]=====\n", i++); ++ buf += sprintf(buf, "[SB: 1] [CP: 2] [NAT: %d] [SIT: %d] ", ++ si->nat_area_segs, si->sit_area_segs); ++ buf += sprintf(buf, "[SSA: %d] [MAIN: %d", ++ si->ssa_area_segs, si->main_area_segs); ++ buf += sprintf(buf, "(OverProv:%d Resv:%d)]\n\n", ++ si->overp_segs, si->rsvd_segs); ++ buf += sprintf(buf, "Utilization: %d%% (%d valid blocks)\n", ++ si->utilization, si->valid_count); ++ buf += sprintf(buf, " - Node: %u (Inode: %u, ", ++ si->valid_node_count, si->valid_inode_count); ++ buf += sprintf(buf, "Other: %u)\n - Data: %u\n", ++ si->valid_node_count - si->valid_inode_count, ++ si->valid_count - si->valid_node_count); ++ buf += sprintf(buf, "\nMain area: %d segs, %d secs %d zones\n", ++ si->main_area_segs, si->main_area_sections, ++ si->main_area_zones); ++ buf += sprintf(buf, " - COLD data: %d, %d, %d\n", ++ si->curseg[CURSEG_COLD_DATA], ++ si->cursec[CURSEG_COLD_DATA], ++ si->curzone[CURSEG_COLD_DATA]); ++ buf += sprintf(buf, " - WARM data: %d, %d, %d\n", ++ si->curseg[CURSEG_WARM_DATA], ++ si->cursec[CURSEG_WARM_DATA], ++ si->curzone[CURSEG_WARM_DATA]); ++ buf += sprintf(buf, " - HOT data: %d, %d, %d\n", ++ si->curseg[CURSEG_HOT_DATA], ++ si->cursec[CURSEG_HOT_DATA], ++ si->curzone[CURSEG_HOT_DATA]); ++ buf += sprintf(buf, " - Dir dnode: %d, %d, %d\n", ++ si->curseg[CURSEG_HOT_NODE], ++ si->cursec[CURSEG_HOT_NODE], ++ si->curzone[CURSEG_HOT_NODE]); ++ buf += sprintf(buf, " - File dnode: %d, %d, %d\n", ++ si->curseg[CURSEG_WARM_NODE], ++ si->cursec[CURSEG_WARM_NODE], ++ si->curzone[CURSEG_WARM_NODE]); ++ buf += sprintf(buf, " - Indir nodes: %d, %d, %d\n", ++ si->curseg[CURSEG_COLD_NODE], ++ si->cursec[CURSEG_COLD_NODE], ++ si->curzone[CURSEG_COLD_NODE]); ++ buf += sprintf(buf, "\n - Valid: %d\n - Dirty: %d\n", ++ si->main_area_segs - si->dirty_count - ++ si->prefree_count - si->free_segs, ++ si->dirty_count); ++ buf += sprintf(buf, " - Prefree: %d\n - Free: %d (%d)\n\n", ++ si->prefree_count, ++ si->free_segs, ++ si->free_secs); ++ buf += sprintf(buf, "GC calls: %d (BG: %d)\n", ++ si->call_count, si->bg_gc); ++ buf += sprintf(buf, " - data segments : %d\n", si->data_segs); ++ buf += sprintf(buf, " - node segments : %d\n", si->node_segs); ++ buf += sprintf(buf, "Try to move %d blocks\n", si->tot_blks); ++ buf += sprintf(buf, " - data blocks : %d\n", si->data_blks); ++ buf += sprintf(buf, " - node blocks : %d\n", si->node_blks); ++ buf += sprintf(buf, "\nExtent Hit Ratio: %d / %d\n", ++ si->hit_ext, si->total_ext); ++ buf += sprintf(buf, "\nBalancing F2FS Async:\n"); ++ buf += sprintf(buf, " - nodes %4d in %4d\n", ++ si->ndirty_node, si->node_pages); ++ buf += sprintf(buf, " - dents %4d in dirs:%4d\n", ++ si->ndirty_dent, si->ndirty_dirs); ++ buf += sprintf(buf, " - meta %4d in %4d\n", ++ si->ndirty_meta, si->meta_pages); ++ buf += sprintf(buf, " - NATs %5d > %lu\n", ++ si->nats, NM_WOUT_THRESHOLD); ++ buf += sprintf(buf, " - SITs: %5d\n - free_nids: %5d\n", ++ si->sits, si->fnids); ++ buf += sprintf(buf, "\nDistribution of User Blocks:"); ++ buf += sprintf(buf, " [ valid | invalid | free ]\n"); ++ buf += sprintf(buf, " ["); ++ for (j = 0; j < si->util_valid; j++) ++ buf += sprintf(buf, "-"); ++ buf += sprintf(buf, "|"); ++ for (j = 0; j < si->util_invalid; j++) ++ buf += sprintf(buf, "-"); ++ buf += sprintf(buf, "|"); ++ for (j = 0; j < si->util_free; j++) ++ buf += sprintf(buf, "-"); ++ buf += sprintf(buf, "]\n\n"); ++ buf += sprintf(buf, "SSR: %u blocks in %u segments\n", ++ si->block_count[SSR], si->segment_count[SSR]); ++ buf += sprintf(buf, "LFS: %u blocks in %u segments\n", ++ si->block_count[LFS], si->segment_count[LFS]); ++ mutex_unlock(&si->stat_list); ++ } ++ return buf - page; ++} ++ ++static int f2fs_read_sit(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct f2fs_gc_info *gc_i, *next; ++ struct f2fs_stat_info *si; ++ char *buf = page; ++ ++ list_for_each_entry_safe(gc_i, next, &f2fs_stat_list, stat_list) { ++ si = gc_i->stat_info; ++ ++ mutex_lock(&si->stat_list); ++ if (!si->sbi) { ++ mutex_unlock(&si->stat_list); ++ continue; ++ } ++ f2fs_update_gc_metric(si->sbi); ++ ++ buf += sprintf(buf, "BDF: %u, avg. vblocks: %u\n", ++ si->bimodal, si->avg_vblocks); ++ mutex_unlock(&si->stat_list); ++ } ++ return buf - page; ++} ++ ++static int f2fs_read_mem(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct f2fs_gc_info *gc_i, *next; ++ struct f2fs_stat_info *si; ++ char *buf = page; ++ ++ list_for_each_entry_safe(gc_i, next, &f2fs_stat_list, stat_list) { ++ struct f2fs_sb_info *sbi = gc_i->stat_info->sbi; ++ unsigned npages; ++ unsigned base_mem = 0, cache_mem = 0; ++ ++ si = gc_i->stat_info; ++ mutex_lock(&si->stat_list); ++ if (!si->sbi) { ++ mutex_unlock(&si->stat_list); ++ continue; ++ } ++ base_mem += sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize; ++ base_mem += 2 * sizeof(struct f2fs_inode_info); ++ base_mem += sizeof(*sbi->ckpt); ++ ++ /* build sm */ ++ base_mem += sizeof(struct f2fs_sm_info); ++ ++ /* build sit */ ++ base_mem += sizeof(struct sit_info); ++ base_mem += TOTAL_SEGS(sbi) * sizeof(struct seg_entry); ++ base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi)); ++ base_mem += 2 * SIT_VBLOCK_MAP_SIZE * TOTAL_SEGS(sbi); ++ if (sbi->segs_per_sec > 1) ++ base_mem += sbi->total_sections * ++ sizeof(struct sec_entry); ++ base_mem += __bitmap_size(sbi, SIT_BITMAP); ++ ++ /* build free segmap */ ++ base_mem += sizeof(struct free_segmap_info); ++ base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi)); ++ base_mem += f2fs_bitmap_size(sbi->total_sections); ++ ++ /* build curseg */ ++ base_mem += sizeof(struct curseg_info) * NR_CURSEG_TYPE; ++ base_mem += PAGE_CACHE_SIZE * NR_CURSEG_TYPE; ++ ++ /* build dirty segmap */ ++ base_mem += sizeof(struct dirty_seglist_info); ++ base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(TOTAL_SEGS(sbi)); ++ base_mem += 2 * f2fs_bitmap_size(TOTAL_SEGS(sbi)); ++ ++ /* buld nm */ ++ base_mem += sizeof(struct f2fs_nm_info); ++ base_mem += __bitmap_size(sbi, NAT_BITMAP); ++ ++ /* build gc */ ++ base_mem += sizeof(struct f2fs_gc_info); ++ base_mem += sizeof(struct f2fs_gc_kthread); ++ ++ /* free nids */ ++ cache_mem += NM_I(sbi)->fcnt; ++ cache_mem += NM_I(sbi)->nat_cnt; ++ npages = sbi->node_inode->i_mapping->nrpages; ++ cache_mem += npages << PAGE_CACHE_SHIFT; ++ npages = sbi->meta_inode->i_mapping->nrpages; ++ cache_mem += npages << PAGE_CACHE_SHIFT; ++ cache_mem += sbi->n_orphans * sizeof(struct orphan_inode_entry); ++ cache_mem += sbi->n_dirty_dirs * sizeof(struct dir_inode_entry); ++ ++ buf += sprintf(buf, "%u KB = static: %u + cached: %u\n", ++ (base_mem + cache_mem) >> 10, ++ base_mem >> 10, ++ cache_mem >> 10); ++ mutex_unlock(&si->stat_list); ++ } ++ return buf - page; ++} ++ ++int f2fs_stat_init(struct f2fs_sb_info *sbi) ++{ ++ struct proc_dir_entry *entry; ++ ++ entry = create_proc_entry("f2fs_stat", 0, sbi->s_proc); ++ if (!entry) ++ return -ENOMEM; ++ entry->read_proc = f2fs_read_gc; ++ entry->write_proc = NULL; ++ ++ entry = create_proc_entry("f2fs_sit_stat", 0, sbi->s_proc); ++ if (!entry) { ++ remove_proc_entry("f2fs_stat", sbi->s_proc); ++ return -ENOMEM; ++ } ++ entry->read_proc = f2fs_read_sit; ++ entry->write_proc = NULL; ++ entry = create_proc_entry("f2fs_mem_stat", 0, sbi->s_proc); ++ if (!entry) { ++ remove_proc_entry("f2fs_sit_stat", sbi->s_proc); ++ remove_proc_entry("f2fs_stat", sbi->s_proc); ++ return -ENOMEM; ++ } ++ entry->read_proc = f2fs_read_mem; ++ entry->write_proc = NULL; ++ return 0; ++} ++ ++void f2fs_stat_exit(struct f2fs_sb_info *sbi) ++{ ++ if (sbi->s_proc) { ++ remove_proc_entry("f2fs_stat", sbi->s_proc); ++ remove_proc_entry("f2fs_sit_stat", sbi->s_proc); ++ remove_proc_entry("f2fs_mem_stat", sbi->s_proc); ++ } ++} ++#endif ++ ++int build_gc_manager(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_gc_info *gc_i; ++ struct f2fs_checkpoint *ckp = F2FS_CKPT(sbi); ++#ifdef CONFIG_F2FS_STAT_FS ++ struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); ++ struct f2fs_stat_info *si; ++#endif ++ ++ gc_i = kzalloc(sizeof(struct f2fs_gc_info), GFP_KERNEL); ++ if (!gc_i) ++ return -ENOMEM; ++ ++ sbi->gc_info = gc_i; ++ gc_i->rsvd_segment_count = le32_to_cpu(ckp->rsvd_segment_count); ++ gc_i->overp_segment_count = le32_to_cpu(ckp->overprov_segment_count); ++ ++ DIRTY_I(sbi)->v_ops = &default_v_ops; ++ ++#ifdef CONFIG_F2FS_STAT_FS ++ gc_i->stat_info = kzalloc(sizeof(struct f2fs_stat_info), ++ GFP_KERNEL); ++ if (!gc_i->stat_info) ++ return -ENOMEM; ++ si = gc_i->stat_info; ++ mutex_init(&si->stat_list); ++ list_add_tail(&gc_i->stat_list, &f2fs_stat_list); ++ ++ si->all_area_segs = le32_to_cpu(raw_super->segment_count); ++ si->sit_area_segs = le32_to_cpu(raw_super->segment_count_sit); ++ si->nat_area_segs = le32_to_cpu(raw_super->segment_count_nat); ++ si->ssa_area_segs = le32_to_cpu(raw_super->segment_count_ssa); ++ si->main_area_segs = le32_to_cpu(raw_super->segment_count_main); ++ si->main_area_sections = le32_to_cpu(raw_super->section_count); ++ si->main_area_zones = si->main_area_sections / ++ le32_to_cpu(raw_super->secs_per_zone); ++ si->sbi = sbi; ++#endif ++ return 0; ++} ++ ++void destroy_gc_manager(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_gc_info *gc_i = sbi->gc_info; ++#ifdef CONFIG_F2FS_STAT_FS ++ struct f2fs_stat_info *si = gc_i->stat_info; ++#endif ++ if (!gc_i) ++ return; ++ ++#ifdef CONFIG_F2FS_STAT_FS ++ list_del(&gc_i->stat_list); ++ mutex_lock(&si->stat_list); ++ si->sbi = NULL; ++ mutex_unlock(&si->stat_list); ++ kfree(gc_i->stat_info); ++#endif ++ sbi->gc_info = NULL; ++ kfree(gc_i); ++} ++ ++int create_gc_caches(void) ++{ ++ winode_slab = f2fs_kmem_cache_create("f2fs_gc_inodes", ++ sizeof(struct inode_entry), NULL); ++ if (!winode_slab) ++ return -ENOMEM; ++ return 0; ++} ++ ++void destroy_gc_caches(void) ++{ ++ kmem_cache_destroy(winode_slab); ++} +diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h +new file mode 100644 +index 0000000..29b345d +--- /dev/null ++++ b/fs/f2fs/gc.h +@@ -0,0 +1,203 @@ ++/** ++ * fs/f2fs/gc.h ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#define GC_THREAD_NAME "f2fs_gc_task" ++#define GC_THREAD_MIN_WB_PAGES 1 /* ++ * a threshold to determine ++ * whether IO subsystem is idle ++ * or not ++ */ ++#define GC_THREAD_MIN_SLEEP_TIME 10000 /* milliseconds */ ++#define GC_THREAD_MAX_SLEEP_TIME 30000 ++#define GC_THREAD_NOGC_SLEEP_TIME 10000 ++#define LIMIT_INVALID_BLOCK 40 /* percentage over total user space */ ++#define LIMIT_FREE_BLOCK 40 /* percentage over invalid + free space */ ++ ++/* Search max. number of dirty segments to select a victim segment */ ++#define MAX_VICTIM_SEARCH 20 ++ ++enum { ++ GC_NONE = 0, ++ GC_ERROR, ++ GC_OK, ++ GC_NEXT, ++ GC_BLOCKED, ++ GC_DONE, ++}; ++ ++#ifdef CONFIG_F2FS_STAT_FS ++struct f2fs_stat_info { ++ struct f2fs_sb_info *sbi; ++ struct mutex stat_list; ++ int all_area_segs; ++ int sit_area_segs; ++ int nat_area_segs; ++ int ssa_area_segs; ++ int main_area_segs; ++ int main_area_sections; ++ int main_area_zones; ++ int hit_ext, total_ext; ++ int ndirty_node; ++ int ndirty_dent; ++ int ndirty_dirs; ++ int ndirty_meta; ++ int nats, sits, fnids; ++ int total_count; ++ int utilization; ++ int bg_gc; ++ unsigned int valid_count; ++ unsigned int valid_node_count; ++ unsigned int valid_inode_count; ++ unsigned int bimodal, avg_vblocks; ++ int util_free, util_valid, util_invalid; ++ int rsvd_segs, overp_segs; ++ int dirty_count; ++ int node_pages; ++ int meta_pages; ++ int prefree_count; ++ int call_count; ++ int tot_segs; ++ int node_segs; ++ int data_segs; ++ int free_segs; ++ int free_secs; ++ int tot_blks; ++ int data_blks; ++ int node_blks; ++ int curseg[6]; ++ int cursec[6]; ++ int curzone[6]; ++ ++ unsigned int segment_count[2]; ++ unsigned int block_count[2]; ++}; ++ ++#define GC_STAT_I(gi) ((gi)->stat_info) ++ ++#define gc_stat_inc_call_count(gi) ((GC_STAT_I(gi))->call_count++) ++ ++#define gc_stat_inc_seg_count(sbi, type) \ ++ do { \ ++ struct f2fs_gc_info *gi = sbi->gc_info; \ ++ GC_STAT_I(gi)->tot_segs++; \ ++ if (type == SUM_TYPE_DATA) \ ++ GC_STAT_I(gi)->data_segs++; \ ++ else \ ++ GC_STAT_I(gi)->node_segs++; \ ++ } while (0) ++ ++#define gc_stat_inc_tot_blk_count(gi, blks) \ ++ ((GC_STAT_I(gi)->tot_blks) += (blks)) ++ ++#define gc_stat_inc_data_blk_count(sbi, blks) \ ++ do { \ ++ struct f2fs_gc_info *gi = sbi->gc_info; \ ++ gc_stat_inc_tot_blk_count(gi, blks); \ ++ GC_STAT_I(gi)->data_blks += (blks); \ ++ } while (0) ++ ++#define gc_stat_inc_node_blk_count(sbi, blks) \ ++ do { \ ++ struct f2fs_gc_info *gi = sbi->gc_info; \ ++ gc_stat_inc_tot_blk_count(gi, blks); \ ++ GC_STAT_I(gi)->node_blks += (blks); \ ++ } while (0) ++ ++#else ++#define gc_stat_inc_call_count(gi) ++#define gc_stat_inc_seg_count(gi, type) ++#define gc_stat_inc_tot_blk_count(gi, blks) ++#define gc_stat_inc_data_blk_count(gi, blks) ++#define gc_stat_inc_node_blk_count(sbi, blks) ++#endif ++ ++struct f2fs_gc_kthread { ++ struct task_struct *f2fs_gc_task; ++ wait_queue_head_t gc_wait_queue_head; ++}; ++ ++struct inode_entry { ++ struct list_head list; ++ struct inode *inode; ++}; ++ ++/** ++ * inline functions ++ */ ++static inline block_t free_user_blocks(struct f2fs_sb_info *sbi) ++{ ++ if (free_segments(sbi) < overprovision_segments(sbi)) ++ return 0; ++ else ++ return (free_segments(sbi) - overprovision_segments(sbi)) ++ << sbi->log_blocks_per_seg; ++} ++ ++static inline block_t limit_invalid_user_blocks(struct f2fs_sb_info *sbi) ++{ ++ return (long)(sbi->user_block_count * LIMIT_INVALID_BLOCK) / 100; ++} ++ ++static inline block_t limit_free_user_blocks(struct f2fs_sb_info *sbi) ++{ ++ block_t reclaimable_user_blocks = sbi->user_block_count - ++ written_block_count(sbi); ++ return (long)(reclaimable_user_blocks * LIMIT_FREE_BLOCK) / 100; ++} ++ ++static inline long increase_sleep_time(long wait) ++{ ++ wait += GC_THREAD_MIN_SLEEP_TIME; ++ if (wait > GC_THREAD_MAX_SLEEP_TIME) ++ wait = GC_THREAD_MAX_SLEEP_TIME; ++ return wait; ++} ++ ++static inline long decrease_sleep_time(long wait) ++{ ++ wait -= GC_THREAD_MIN_SLEEP_TIME; ++ if (wait <= GC_THREAD_MIN_SLEEP_TIME) ++ wait = GC_THREAD_MIN_SLEEP_TIME; ++ return wait; ++} ++ ++static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi) ++{ ++ block_t invalid_user_blocks = sbi->user_block_count - ++ written_block_count(sbi); ++ /* ++ * Background GC is triggered with the following condition. ++ * 1. There are a number of invalid blocks. ++ * 2. There is not enough free space. ++ */ ++ if (invalid_user_blocks > limit_invalid_user_blocks(sbi) && ++ free_user_blocks(sbi) < limit_free_user_blocks(sbi)) ++ return true; ++ return false; ++} ++ ++static inline int is_idle(struct f2fs_sb_info *sbi) ++{ ++ struct block_device *bdev = sbi->sb->s_bdev; ++ struct request_queue *q = bdev_get_queue(bdev); ++ struct request_list *rl = &q->root_rl; ++ return !(rl->count[BLK_RW_SYNC]) && !(rl->count[BLK_RW_ASYNC]); ++} ++ ++static bool should_do_checkpoint(struct f2fs_sb_info *sbi) ++{ ++ unsigned int pages_per_sec = sbi->segs_per_sec * ++ (1 << sbi->log_blocks_per_seg); ++ int node_secs = ((get_pages(sbi, F2FS_DIRTY_NODES) + pages_per_sec - 1) ++ >> sbi->log_blocks_per_seg) / sbi->segs_per_sec; ++ int dent_secs = ((get_pages(sbi, F2FS_DIRTY_DENTS) + pages_per_sec - 1) ++ >> sbi->log_blocks_per_seg) / sbi->segs_per_sec; ++ return free_sections(sbi) <= (node_secs + 2 * dent_secs + 2); ++} diff --git a/patches/linux-3.7-rc6/0112-f2fs-add-recovery-routines-for-roll-forward.patch b/patches/linux-3.7-rc6/0112-f2fs-add-recovery-routines-for-roll-forward.patch new file mode 100644 index 0000000..39a629a --- /dev/null +++ b/patches/linux-3.7-rc6/0112-f2fs-add-recovery-routines-for-roll-forward.patch @@ -0,0 +1,411 @@ +From a458712f9bd670469b3aa1c474bbdc48465af27c Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:32:56 +0000 +Subject: [PATCH] f2fs: add recovery routines for roll-forward + +This adds roll-forward routines to recover fsynced data. + +- F2FS uses basically roll-back model with checkpointing. + +- In order to implement fsync(), there are two approaches as follows. + +1. A roll-back model with checkpointing at every fsync() + : This is a naive method, but suffers from very low performance. + +2. A roll-forward model + : F2FS adopts this model where all the fsynced data should be recovered, which + were written after checkpointing was done. In order to figure out the data, + F2FS keeps a "fsync" mark in direct node blocks. In addition, F2FS remains + the location of next node block in each direct node block for reconstructing + the chain of node blocks during the recovery. + +- In order to enhance the performance, F2FS keeps a "dentry" mark also in direct + node blocks. If this is set during the recovery, F2FS replays adding a dentry. + +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/f2fs/recovery.c | 375 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 375 insertions(+) + create mode 100644 fs/f2fs/recovery.c + +diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c +new file mode 100644 +index 0000000..59b6331 +--- /dev/null ++++ b/fs/f2fs/recovery.c +@@ -0,0 +1,375 @@ ++/** ++ * fs/f2fs/recovery.c ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/fs.h> ++#include <linux/f2fs_fs.h> ++#include "f2fs.h" ++#include "node.h" ++#include "segment.h" ++ ++static struct kmem_cache *fsync_entry_slab; ++ ++bool space_for_roll_forward(struct f2fs_sb_info *sbi) ++{ ++ if (sbi->last_valid_block_count + sbi->alloc_valid_block_count ++ > sbi->user_block_count) ++ return false; ++ return true; ++} ++ ++static struct fsync_inode_entry *get_fsync_inode(struct list_head *head, ++ nid_t ino) ++{ ++ struct list_head *this; ++ struct fsync_inode_entry *entry; ++ ++ list_for_each(this, head) { ++ entry = list_entry(this, struct fsync_inode_entry, list); ++ if (entry->inode->i_ino == ino) ++ return entry; ++ } ++ return NULL; ++} ++ ++static int recover_dentry(struct page *ipage, struct inode *inode) ++{ ++ struct f2fs_node *raw_node = (struct f2fs_node *)kmap(ipage); ++ struct f2fs_inode *raw_inode = &(raw_node->i); ++ struct dentry dent, parent; ++ struct f2fs_dir_entry *de; ++ struct page *page; ++ struct inode *dir; ++ int err = 0; ++ ++ if (!is_dent_dnode(ipage)) ++ goto out; ++ ++ dir = f2fs_iget(inode->i_sb, le32_to_cpu(raw_inode->i_pino)); ++ if (IS_ERR(dir)) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ parent.d_inode = dir; ++ dent.d_parent = &parent; ++ dent.d_name.len = le32_to_cpu(raw_inode->i_namelen); ++ dent.d_name.name = raw_inode->i_name; ++ ++ de = f2fs_find_entry(dir, &dent.d_name, &page); ++ if (de) { ++ kunmap(page); ++ f2fs_put_page(page, 0); ++ } else { ++ f2fs_add_link(&dent, inode); ++ } ++ iput(dir); ++out: ++ kunmap(ipage); ++ return err; ++} ++ ++static int recover_inode(struct inode *inode, struct page *node_page) ++{ ++ void *kaddr = page_address(node_page); ++ struct f2fs_node *raw_node = (struct f2fs_node *)kaddr; ++ struct f2fs_inode *raw_inode = &(raw_node->i); ++ ++ inode->i_mode = le32_to_cpu(raw_inode->i_mode); ++ i_size_write(inode, le64_to_cpu(raw_inode->i_size)); ++ inode->i_atime.tv_sec = le64_to_cpu(raw_inode->i_mtime); ++ inode->i_ctime.tv_sec = le64_to_cpu(raw_inode->i_ctime); ++ inode->i_mtime.tv_sec = le64_to_cpu(raw_inode->i_mtime); ++ inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); ++ inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec); ++ inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); ++ ++ return recover_dentry(node_page, inode); ++} ++ ++static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) ++{ ++ unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver); ++ struct curseg_info *curseg; ++ struct page *page; ++ block_t blkaddr; ++ int err = 0; ++ ++ /* get node pages in the current segment */ ++ curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); ++ blkaddr = START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff; ++ ++ /* read node page */ ++ page = alloc_page(GFP_NOFS | __GFP_ZERO); ++ if (IS_ERR(page)) ++ return PTR_ERR(page); ++ lock_page(page); ++ ++ while (1) { ++ struct fsync_inode_entry *entry; ++ ++ if (f2fs_readpage(sbi, page, blkaddr, READ_SYNC)) ++ goto out; ++ ++ if (cp_ver != cpver_of_node(page)) ++ goto out; ++ ++ if (!is_fsync_dnode(page)) ++ goto next; ++ ++ entry = get_fsync_inode(head, ino_of_node(page)); ++ if (entry) { ++ entry->blkaddr = blkaddr; ++ if (IS_INODE(page) && is_dent_dnode(page)) ++ set_inode_flag(F2FS_I(entry->inode), ++ FI_INC_LINK); ++ } else { ++ if (IS_INODE(page) && is_dent_dnode(page)) { ++ if (recover_inode_page(sbi, page)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ } ++ ++ /* add this fsync inode to the list */ ++ entry = kmem_cache_alloc(fsync_entry_slab, GFP_NOFS); ++ if (!entry) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ INIT_LIST_HEAD(&entry->list); ++ list_add_tail(&entry->list, head); ++ ++ entry->inode = f2fs_iget(sbi->sb, ino_of_node(page)); ++ if (IS_ERR(entry->inode)) { ++ err = PTR_ERR(entry->inode); ++ goto out; ++ } ++ entry->blkaddr = blkaddr; ++ } ++ if (IS_INODE(page)) { ++ err = recover_inode(entry->inode, page); ++ if (err) ++ goto out; ++ } ++next: ++ /* check next segment */ ++ blkaddr = next_blkaddr_of_node(page); ++ ClearPageUptodate(page); ++ } ++out: ++ unlock_page(page); ++ __free_pages(page, 0); ++ return err; ++} ++ ++static void destroy_fsync_dnodes(struct f2fs_sb_info *sbi, ++ struct list_head *head) ++{ ++ struct list_head *this; ++ struct fsync_inode_entry *entry; ++ list_for_each(this, head) { ++ entry = list_entry(this, struct fsync_inode_entry, list); ++ iput(entry->inode); ++ list_del(&entry->list); ++ kmem_cache_free(fsync_entry_slab, entry); ++ } ++} ++ ++static void check_index_in_prev_nodes(struct f2fs_sb_info *sbi, ++ block_t blkaddr) ++{ ++ struct seg_entry *sentry; ++ unsigned int segno = GET_SEGNO(sbi, blkaddr); ++ unsigned short blkoff = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) & ++ (sbi->blocks_per_seg - 1); ++ struct f2fs_summary sum; ++ nid_t ino; ++ void *kaddr; ++ struct inode *inode; ++ struct page *node_page; ++ block_t bidx; ++ int i; ++ ++ sentry = get_seg_entry(sbi, segno); ++ if (!f2fs_test_bit(blkoff, sentry->cur_valid_map)) ++ return; ++ ++ /* Get the previous summary */ ++ for (i = CURSEG_WARM_DATA; i <= CURSEG_COLD_DATA; i++) { ++ struct curseg_info *curseg = CURSEG_I(sbi, i); ++ if (curseg->segno == segno) { ++ sum = curseg->sum_blk->entries[blkoff]; ++ break; ++ } ++ } ++ if (i > CURSEG_COLD_DATA) { ++ struct page *sum_page = get_sum_page(sbi, segno); ++ struct f2fs_summary_block *sum_node; ++ kaddr = page_address(sum_page); ++ sum_node = (struct f2fs_summary_block *)kaddr; ++ sum = sum_node->entries[blkoff]; ++ f2fs_put_page(sum_page, 1); ++ } ++ ++ /* Get the node page */ ++ node_page = get_node_page(sbi, le32_to_cpu(sum.nid)); ++ bidx = start_bidx_of_node(ofs_of_node(node_page)) + ++ le16_to_cpu(sum.ofs_in_node); ++ ino = ino_of_node(node_page); ++ f2fs_put_page(node_page, 1); ++ ++ /* Deallocate previous index in the node page */ ++ inode = f2fs_iget_nowait(sbi->sb, ino); ++ truncate_hole(inode, bidx, bidx + 1); ++ iput(inode); ++} ++ ++static void do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, ++ struct page *page, block_t blkaddr) ++{ ++ unsigned int start, end; ++ struct dnode_of_data dn; ++ struct f2fs_summary sum; ++ struct node_info ni; ++ ++ start = start_bidx_of_node(ofs_of_node(page)); ++ if (IS_INODE(page)) ++ end = start + ADDRS_PER_INODE; ++ else ++ end = start + ADDRS_PER_BLOCK; ++ ++ set_new_dnode(&dn, inode, NULL, NULL, 0); ++ if (get_dnode_of_data(&dn, start, 0)) ++ return; ++ ++ wait_on_page_writeback(dn.node_page); ++ ++ get_node_info(sbi, dn.nid, &ni); ++ BUG_ON(ni.ino != ino_of_node(page)); ++ BUG_ON(ofs_of_node(dn.node_page) != ofs_of_node(page)); ++ ++ for (; start < end; start++) { ++ block_t src, dest; ++ ++ src = datablock_addr(dn.node_page, dn.ofs_in_node); ++ dest = datablock_addr(page, dn.ofs_in_node); ++ ++ if (src != dest && dest != NEW_ADDR && dest != NULL_ADDR) { ++ if (src == NULL_ADDR) { ++ int err = reserve_new_block(&dn); ++ /* We should not get -ENOSPC */ ++ BUG_ON(err); ++ } ++ ++ /* Check the previous node page having this index */ ++ check_index_in_prev_nodes(sbi, dest); ++ ++ set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version); ++ ++ /* write dummy data page */ ++ recover_data_page(sbi, NULL, &sum, src, dest); ++ update_extent_cache(dest, &dn); ++ } ++ dn.ofs_in_node++; ++ } ++ ++ /* write node page in place */ ++ set_summary(&sum, dn.nid, 0, 0); ++ if (IS_INODE(dn.node_page)) ++ sync_inode_page(&dn); ++ ++ copy_node_footer(dn.node_page, page); ++ fill_node_footer(dn.node_page, dn.nid, ni.ino, ++ ofs_of_node(page), false); ++ set_page_dirty(dn.node_page); ++ ++ recover_node_page(sbi, dn.node_page, &sum, &ni, blkaddr); ++ f2fs_put_dnode(&dn); ++} ++ ++static void recover_data(struct f2fs_sb_info *sbi, ++ struct list_head *head, int type) ++{ ++ unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver); ++ struct curseg_info *curseg; ++ struct page *page; ++ block_t blkaddr; ++ ++ /* get node pages in the current segment */ ++ curseg = CURSEG_I(sbi, type); ++ blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); ++ ++ /* read node page */ ++ page = alloc_page(GFP_NOFS | __GFP_ZERO); ++ if (IS_ERR(page)) ++ return; ++ lock_page(page); ++ ++ while (1) { ++ struct fsync_inode_entry *entry; ++ ++ if (f2fs_readpage(sbi, page, blkaddr, READ_SYNC)) ++ goto out; ++ ++ if (cp_ver != cpver_of_node(page)) ++ goto out; ++ ++ entry = get_fsync_inode(head, ino_of_node(page)); ++ if (!entry) ++ goto next; ++ ++ do_recover_data(sbi, entry->inode, page, blkaddr); ++ ++ if (entry->blkaddr == blkaddr) { ++ iput(entry->inode); ++ list_del(&entry->list); ++ kmem_cache_free(fsync_entry_slab, entry); ++ } ++next: ++ /* check next segment */ ++ blkaddr = next_blkaddr_of_node(page); ++ ClearPageUptodate(page); ++ } ++out: ++ unlock_page(page); ++ __free_pages(page, 0); ++ ++ allocate_new_segments(sbi); ++} ++ ++void recover_fsync_data(struct f2fs_sb_info *sbi) ++{ ++ struct list_head inode_list; ++ ++ fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", ++ sizeof(struct fsync_inode_entry), NULL); ++ if (unlikely(!fsync_entry_slab)) ++ return; ++ ++ INIT_LIST_HEAD(&inode_list); ++ ++ /* step #1: find fsynced inode numbers */ ++ if (find_fsync_dnodes(sbi, &inode_list)) ++ goto out; ++ ++ if (list_empty(&inode_list)) ++ goto out; ++ ++ /* step #2: recover data */ ++ sbi->por_doing = 1; ++ recover_data(sbi, &inode_list, CURSEG_WARM_NODE); ++ sbi->por_doing = 0; ++ BUG_ON(!list_empty(&inode_list)); ++out: ++ destroy_fsync_dnodes(sbi, &inode_list); ++ kmem_cache_destroy(fsync_entry_slab); ++ write_checkpoint(sbi, false, false); ++} diff --git a/patches/linux-3.7-rc6/0113-f2fs-update-Kconfig-and-Makefile.patch b/patches/linux-3.7-rc6/0113-f2fs-update-Kconfig-and-Makefile.patch new file mode 100644 index 0000000..263eef8 --- /dev/null +++ b/patches/linux-3.7-rc6/0113-f2fs-update-Kconfig-and-Makefile.patch @@ -0,0 +1,115 @@ +From 4c78c6c29f9986e46020c04c8741db373565f473 Mon Sep 17 00:00:00 2001 +From: ??? <jaegeuk.kim@samsung.com> +Date: Tue, 23 Oct 2012 02:33:28 +0000 +Subject: [PATCH] f2fs: update Kconfig and Makefile + +This adds Makefile and Kconfig for f2fs, and updates Makefile and Kconfig files +in the fs directory. + +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +--- + fs/Kconfig | 1 + + fs/Makefile | 1 + + fs/f2fs/Kconfig | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/f2fs/Makefile | 6 ++++++ + 4 files changed, 63 insertions(+) + create mode 100644 fs/f2fs/Kconfig + create mode 100644 fs/f2fs/Makefile + +diff --git a/fs/Kconfig b/fs/Kconfig +index f95ae3a..e352b37 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -220,6 +220,7 @@ source "fs/pstore/Kconfig" + source "fs/sysv/Kconfig" + source "fs/ufs/Kconfig" + source "fs/exofs/Kconfig" ++source "fs/f2fs/Kconfig" + + endif # MISC_FILESYSTEMS + +diff --git a/fs/Makefile b/fs/Makefile +index 1d7af79..9d53192 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -123,6 +123,7 @@ obj-$(CONFIG_DEBUG_FS) += debugfs/ + obj-$(CONFIG_OCFS2_FS) += ocfs2/ + obj-$(CONFIG_BTRFS_FS) += btrfs/ + obj-$(CONFIG_GFS2_FS) += gfs2/ ++obj-$(CONFIG_F2FS_FS) += f2fs/ + obj-y += exofs/ # Multiple modules + obj-$(CONFIG_CEPH_FS) += ceph/ + obj-$(CONFIG_PSTORE) += pstore/ +diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig +new file mode 100644 +index 0000000..8821c6a +--- /dev/null ++++ b/fs/f2fs/Kconfig +@@ -0,0 +1,55 @@ ++config F2FS_FS ++ tristate "F2FS filesystem support (EXPERIMENTAL)" ++ depends on EXPERIMENTAL ++ help ++ F2FS is based on Log-structured File System (LFS), which supports ++ versatile "flash-friendly" features. The design has been focused on ++ addressing the fundamental issues in LFS, which are snowball effect ++ of wandering tree and high cleaning overhead. ++ ++ Since flash-based storages show different characteristics according to ++ the internal geometry or flash memory management schemes aka FTL, F2FS ++ and tools support various parameters not only for configuring on-disk ++ layout, but also for selecting allocation and cleaning algorithms. ++ ++ If unsure, say N. ++ ++config F2FS_STAT_FS ++ bool "F2FS Status Information" ++ depends on F2FS_FS ++ default y ++ help ++ /proc/fs/f2fs/ contains information about partitions mounted as f2fs. ++ For each partition, a corresponding directory, named as its device ++ name, is provided with the following proc entries. ++ ++ f2fs_stat major file system information managed by f2fs currently ++ f2fs_sit_stat average SIT information about whole segments ++ f2fs_mem_stat current memory footprint consumed by f2fs ++ ++ e.g., in /proc/fs/f2fs/sdb1/ ++ ++config F2FS_FS_XATTR ++ bool "F2FS extended attributes" ++ depends on F2FS_FS ++ default y ++ help ++ Extended attributes are name:value pairs associated with inodes by ++ the kernel or by users (see the attr(5) manual page, or visit ++ <http://acl.bestbits.at/> for details). ++ ++ If unsure, say N. ++ ++config F2FS_FS_POSIX_ACL ++ bool "F2FS Access Control Lists" ++ depends on F2FS_FS_XATTR ++ select FS_POSIX_ACL ++ default y ++ help ++ Posix Access Control Lists (ACLs) support permissions for users and ++ gourps beyond the owner/group/world scheme. ++ ++ To learn more about Access Control Lists, visit the POSIX ACLs for ++ Linux website <http://acl.bestbits.at/>. ++ ++ If you don't know what Access Control Lists are, say N +diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile +new file mode 100644 +index 0000000..72fcf9a +--- /dev/null ++++ b/fs/f2fs/Makefile +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_F2FS_FS) += f2fs.o ++ ++f2fs-y := dir.o file.o inode.o namei.o hash.o super.o ++f2fs-y += checkpoint.o gc.o data.o node.o segment.o recovery.o ++f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o ++f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o diff --git a/patches/linux-3.7-rc6/0114-f2fs-gc.h-make-should_do_checkpoint-inline.patch b/patches/linux-3.7-rc6/0114-f2fs-gc.h-make-should_do_checkpoint-inline.patch new file mode 100644 index 0000000..66d5782 --- /dev/null +++ b/patches/linux-3.7-rc6/0114-f2fs-gc.h-make-should_do_checkpoint-inline.patch @@ -0,0 +1,26 @@ +From 26e33463d5f5705a2d0159209aff0404b97095c6 Mon Sep 17 00:00:00 2001 +From: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org> +Date: Tue, 23 Oct 2012 18:21:46 +0000 +Subject: [PATCH] f2fs: gc.h: make should_do_checkpoint() inline + +This should be an inline function, not a "real" function. Now other +files can properly include gc.h. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + fs/f2fs/gc.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h +index 29b345d..b70366f 100644 +--- a/fs/f2fs/gc.h ++++ b/fs/f2fs/gc.h +@@ -191,7 +191,7 @@ static inline int is_idle(struct f2fs_sb_info *sbi) + return !(rl->count[BLK_RW_SYNC]) && !(rl->count[BLK_RW_ASYNC]); + } + +-static bool should_do_checkpoint(struct f2fs_sb_info *sbi) ++static inline bool should_do_checkpoint(struct f2fs_sb_info *sbi) + { + unsigned int pages_per_sec = sbi->segs_per_sec * + (1 << sbi->log_blocks_per_seg); diff --git a/patches/linux-3.7-rc6/0115-f2fs-move-statistics-code-into-one-file.patch b/patches/linux-3.7-rc6/0115-f2fs-move-statistics-code-into-one-file.patch new file mode 100644 index 0000000..ec8bdd0 --- /dev/null +++ b/patches/linux-3.7-rc6/0115-f2fs-move-statistics-code-into-one-file.patch @@ -0,0 +1,967 @@ +From b6f5f093ec14b476ba7d0282488391add23365f6 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Tue, 23 Oct 2012 18:22:41 +0000 +Subject: [PATCH] f2fs: move statistics code into one file + +This moves all of the procfs statistics code into one file, debug.c and +removes the #ifdefs from the core f2fs code when calling statistic +functions. + +This will make it more obvious how to move from procfs to debugfs, no +functionality was changed here at all. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + fs/f2fs/Makefile | 1 + + fs/f2fs/debug.c | 414 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/f2fs/f2fs.h | 25 +++- + fs/f2fs/gc.c | 373 +----------------------------------------------- + fs/f2fs/super.c | 21 +-- + 5 files changed, 442 insertions(+), 392 deletions(-) + create mode 100644 fs/f2fs/debug.c + +diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile +index 72fcf9a..27a0820 100644 +--- a/fs/f2fs/Makefile ++++ b/fs/f2fs/Makefile +@@ -2,5 +2,6 @@ obj-$(CONFIG_F2FS_FS) += f2fs.o + + f2fs-y := dir.o file.o inode.o namei.o hash.o super.o + f2fs-y += checkpoint.o gc.o data.o node.o segment.o recovery.o ++f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o + f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o + f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o +diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c +new file mode 100644 +index 0000000..0145b02 +--- /dev/null ++++ b/fs/f2fs/debug.c +@@ -0,0 +1,414 @@ ++/** ++ * f2fs debugging statistics ++ * ++ * Copyright (c) 2012 Samsung Electronics Co., Ltd. ++ * http://www.samsung.com/ ++ * Copyright (c) 2012 Linux Foundation ++ * Copyright (c) 2012 Greg Kroah-Hartman <gregkh@linuxfoundation.org> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/fs.h> ++#include <linux/backing-dev.h> ++#include <linux/proc_fs.h> ++#include <linux/f2fs_fs.h> ++#include <linux/blkdev.h> ++ ++#include "f2fs.h" ++#include "node.h" ++#include "segment.h" ++#include "gc.h" ++ ++static LIST_HEAD(f2fs_stat_list); ++static struct proc_dir_entry *f2fs_proc_root; ++ ++ ++void f2fs_update_stat(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_gc_info *gc_i = sbi->gc_info; ++ struct f2fs_stat_info *si = gc_i->stat_info; ++ int i; ++ ++ /* valid check of the segment numbers */ ++ si->hit_ext = sbi->read_hit_ext; ++ si->total_ext = sbi->total_hit_ext; ++ si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES); ++ si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS); ++ si->ndirty_dirs = sbi->n_dirty_dirs; ++ si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META); ++ si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg; ++ si->rsvd_segs = reserved_segments(sbi); ++ si->overp_segs = overprovision_segments(sbi); ++ si->valid_count = valid_user_blocks(sbi); ++ si->valid_node_count = valid_node_count(sbi); ++ si->valid_inode_count = valid_inode_count(sbi); ++ si->utilization = utilization(sbi); ++ ++ si->free_segs = free_segments(sbi); ++ si->free_secs = free_sections(sbi); ++ si->prefree_count = prefree_segments(sbi); ++ si->dirty_count = dirty_segments(sbi); ++ si->node_pages = sbi->node_inode->i_mapping->nrpages; ++ si->meta_pages = sbi->meta_inode->i_mapping->nrpages; ++ si->nats = NM_I(sbi)->nat_cnt; ++ si->sits = SIT_I(sbi)->dirty_sentries; ++ si->fnids = NM_I(sbi)->fcnt; ++ si->bg_gc = sbi->bg_gc; ++ si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg) ++ * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg) ++ / 2; ++ si->util_valid = (int)(written_block_count(sbi) >> ++ sbi->log_blocks_per_seg) ++ * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg) ++ / 2; ++ si->util_invalid = 50 - si->util_free - si->util_valid; ++ for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_NODE; i++) { ++ struct curseg_info *curseg = CURSEG_I(sbi, i); ++ si->curseg[i] = curseg->segno; ++ si->cursec[i] = curseg->segno / sbi->segs_per_sec; ++ si->curzone[i] = si->cursec[i] / sbi->secs_per_zone; ++ } ++ ++ for (i = 0; i < 2; i++) { ++ si->segment_count[i] = sbi->segment_count[i]; ++ si->block_count[i] = sbi->block_count[i]; ++ } ++} ++ ++/** ++ * This function calculates BDF of every segments ++ */ ++static void f2fs_update_gc_metric(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_gc_info *gc_i = sbi->gc_info; ++ struct f2fs_stat_info *si = gc_i->stat_info; ++ unsigned int blks_per_sec, hblks_per_sec, total_vblocks, bimodal, dist; ++ struct sit_info *sit_i = SIT_I(sbi); ++ unsigned int segno, vblocks; ++ int ndirty = 0; ++ ++ bimodal = 0; ++ total_vblocks = 0; ++ blks_per_sec = sbi->segs_per_sec * (1 << sbi->log_blocks_per_seg); ++ hblks_per_sec = blks_per_sec / 2; ++ mutex_lock(&sit_i->sentry_lock); ++ for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) { ++ vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec); ++ dist = abs(vblocks - hblks_per_sec); ++ bimodal += dist * dist; ++ ++ if (vblocks > 0 && vblocks < blks_per_sec) { ++ total_vblocks += vblocks; ++ ndirty++; ++ } ++ } ++ mutex_unlock(&sit_i->sentry_lock); ++ dist = sbi->total_sections * hblks_per_sec * hblks_per_sec / 100; ++ si->bimodal = bimodal / dist; ++ if (si->dirty_count) ++ si->avg_vblocks = total_vblocks / ndirty; ++ else ++ si->avg_vblocks = 0; ++} ++ ++static int f2fs_read_gc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct f2fs_gc_info *gc_i, *next; ++ struct f2fs_stat_info *si; ++ char *buf = page; ++ int i = 0; ++ ++ list_for_each_entry_safe(gc_i, next, &f2fs_stat_list, stat_list) { ++ int j; ++ si = gc_i->stat_info; ++ ++ mutex_lock(&si->stat_list); ++ if (!si->sbi) { ++ mutex_unlock(&si->stat_list); ++ continue; ++ } ++ f2fs_update_stat(si->sbi); ++ ++ buf += sprintf(buf, "=====[ partition info. #%d ]=====\n", i++); ++ buf += sprintf(buf, "[SB: 1] [CP: 2] [NAT: %d] [SIT: %d] ", ++ si->nat_area_segs, si->sit_area_segs); ++ buf += sprintf(buf, "[SSA: %d] [MAIN: %d", ++ si->ssa_area_segs, si->main_area_segs); ++ buf += sprintf(buf, "(OverProv:%d Resv:%d)]\n\n", ++ si->overp_segs, si->rsvd_segs); ++ buf += sprintf(buf, "Utilization: %d%% (%d valid blocks)\n", ++ si->utilization, si->valid_count); ++ buf += sprintf(buf, " - Node: %u (Inode: %u, ", ++ si->valid_node_count, si->valid_inode_count); ++ buf += sprintf(buf, "Other: %u)\n - Data: %u\n", ++ si->valid_node_count - si->valid_inode_count, ++ si->valid_count - si->valid_node_count); ++ buf += sprintf(buf, "\nMain area: %d segs, %d secs %d zones\n", ++ si->main_area_segs, si->main_area_sections, ++ si->main_area_zones); ++ buf += sprintf(buf, " - COLD data: %d, %d, %d\n", ++ si->curseg[CURSEG_COLD_DATA], ++ si->cursec[CURSEG_COLD_DATA], ++ si->curzone[CURSEG_COLD_DATA]); ++ buf += sprintf(buf, " - WARM data: %d, %d, %d\n", ++ si->curseg[CURSEG_WARM_DATA], ++ si->cursec[CURSEG_WARM_DATA], ++ si->curzone[CURSEG_WARM_DATA]); ++ buf += sprintf(buf, " - HOT data: %d, %d, %d\n", ++ si->curseg[CURSEG_HOT_DATA], ++ si->cursec[CURSEG_HOT_DATA], ++ si->curzone[CURSEG_HOT_DATA]); ++ buf += sprintf(buf, " - Dir dnode: %d, %d, %d\n", ++ si->curseg[CURSEG_HOT_NODE], ++ si->cursec[CURSEG_HOT_NODE], ++ si->curzone[CURSEG_HOT_NODE]); ++ buf += sprintf(buf, " - File dnode: %d, %d, %d\n", ++ si->curseg[CURSEG_WARM_NODE], ++ si->cursec[CURSEG_WARM_NODE], ++ si->curzone[CURSEG_WARM_NODE]); ++ buf += sprintf(buf, " - Indir nodes: %d, %d, %d\n", ++ si->curseg[CURSEG_COLD_NODE], ++ si->cursec[CURSEG_COLD_NODE], ++ si->curzone[CURSEG_COLD_NODE]); ++ buf += sprintf(buf, "\n - Valid: %d\n - Dirty: %d\n", ++ si->main_area_segs - si->dirty_count - ++ si->prefree_count - si->free_segs, ++ si->dirty_count); ++ buf += sprintf(buf, " - Prefree: %d\n - Free: %d (%d)\n\n", ++ si->prefree_count, ++ si->free_segs, ++ si->free_secs); ++ buf += sprintf(buf, "GC calls: %d (BG: %d)\n", ++ si->call_count, si->bg_gc); ++ buf += sprintf(buf, " - data segments : %d\n", si->data_segs); ++ buf += sprintf(buf, " - node segments : %d\n", si->node_segs); ++ buf += sprintf(buf, "Try to move %d blocks\n", si->tot_blks); ++ buf += sprintf(buf, " - data blocks : %d\n", si->data_blks); ++ buf += sprintf(buf, " - node blocks : %d\n", si->node_blks); ++ buf += sprintf(buf, "\nExtent Hit Ratio: %d / %d\n", ++ si->hit_ext, si->total_ext); ++ buf += sprintf(buf, "\nBalancing F2FS Async:\n"); ++ buf += sprintf(buf, " - nodes %4d in %4d\n", ++ si->ndirty_node, si->node_pages); ++ buf += sprintf(buf, " - dents %4d in dirs:%4d\n", ++ si->ndirty_dent, si->ndirty_dirs); ++ buf += sprintf(buf, " - meta %4d in %4d\n", ++ si->ndirty_meta, si->meta_pages); ++ buf += sprintf(buf, " - NATs %5d > %lu\n", ++ si->nats, NM_WOUT_THRESHOLD); ++ buf += sprintf(buf, " - SITs: %5d\n - free_nids: %5d\n", ++ si->sits, si->fnids); ++ buf += sprintf(buf, "\nDistribution of User Blocks:"); ++ buf += sprintf(buf, " [ valid | invalid | free ]\n"); ++ buf += sprintf(buf, " ["); ++ for (j = 0; j < si->util_valid; j++) ++ buf += sprintf(buf, "-"); ++ buf += sprintf(buf, "|"); ++ for (j = 0; j < si->util_invalid; j++) ++ buf += sprintf(buf, "-"); ++ buf += sprintf(buf, "|"); ++ for (j = 0; j < si->util_free; j++) ++ buf += sprintf(buf, "-"); ++ buf += sprintf(buf, "]\n\n"); ++ buf += sprintf(buf, "SSR: %u blocks in %u segments\n", ++ si->block_count[SSR], si->segment_count[SSR]); ++ buf += sprintf(buf, "LFS: %u blocks in %u segments\n", ++ si->block_count[LFS], si->segment_count[LFS]); ++ mutex_unlock(&si->stat_list); ++ } ++ return buf - page; ++} ++ ++static int f2fs_read_sit(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct f2fs_gc_info *gc_i, *next; ++ struct f2fs_stat_info *si; ++ char *buf = page; ++ ++ list_for_each_entry_safe(gc_i, next, &f2fs_stat_list, stat_list) { ++ si = gc_i->stat_info; ++ ++ mutex_lock(&si->stat_list); ++ if (!si->sbi) { ++ mutex_unlock(&si->stat_list); ++ continue; ++ } ++ f2fs_update_gc_metric(si->sbi); ++ ++ buf += sprintf(buf, "BDF: %u, avg. vblocks: %u\n", ++ si->bimodal, si->avg_vblocks); ++ mutex_unlock(&si->stat_list); ++ } ++ return buf - page; ++} ++ ++static int f2fs_read_mem(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct f2fs_gc_info *gc_i, *next; ++ struct f2fs_stat_info *si; ++ char *buf = page; ++ ++ list_for_each_entry_safe(gc_i, next, &f2fs_stat_list, stat_list) { ++ struct f2fs_sb_info *sbi = gc_i->stat_info->sbi; ++ unsigned npages; ++ unsigned base_mem = 0, cache_mem = 0; ++ ++ si = gc_i->stat_info; ++ mutex_lock(&si->stat_list); ++ if (!si->sbi) { ++ mutex_unlock(&si->stat_list); ++ continue; ++ } ++ base_mem += sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize; ++ base_mem += 2 * sizeof(struct f2fs_inode_info); ++ base_mem += sizeof(*sbi->ckpt); ++ ++ /* build sm */ ++ base_mem += sizeof(struct f2fs_sm_info); ++ ++ /* build sit */ ++ base_mem += sizeof(struct sit_info); ++ base_mem += TOTAL_SEGS(sbi) * sizeof(struct seg_entry); ++ base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi)); ++ base_mem += 2 * SIT_VBLOCK_MAP_SIZE * TOTAL_SEGS(sbi); ++ if (sbi->segs_per_sec > 1) ++ base_mem += sbi->total_sections * ++ sizeof(struct sec_entry); ++ base_mem += __bitmap_size(sbi, SIT_BITMAP); ++ ++ /* build free segmap */ ++ base_mem += sizeof(struct free_segmap_info); ++ base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi)); ++ base_mem += f2fs_bitmap_size(sbi->total_sections); ++ ++ /* build curseg */ ++ base_mem += sizeof(struct curseg_info) * NR_CURSEG_TYPE; ++ base_mem += PAGE_CACHE_SIZE * NR_CURSEG_TYPE; ++ ++ /* build dirty segmap */ ++ base_mem += sizeof(struct dirty_seglist_info); ++ base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(TOTAL_SEGS(sbi)); ++ base_mem += 2 * f2fs_bitmap_size(TOTAL_SEGS(sbi)); ++ ++ /* buld nm */ ++ base_mem += sizeof(struct f2fs_nm_info); ++ base_mem += __bitmap_size(sbi, NAT_BITMAP); ++ ++ /* build gc */ ++ base_mem += sizeof(struct f2fs_gc_info); ++ base_mem += sizeof(struct f2fs_gc_kthread); ++ ++ /* free nids */ ++ cache_mem += NM_I(sbi)->fcnt; ++ cache_mem += NM_I(sbi)->nat_cnt; ++ npages = sbi->node_inode->i_mapping->nrpages; ++ cache_mem += npages << PAGE_CACHE_SHIFT; ++ npages = sbi->meta_inode->i_mapping->nrpages; ++ cache_mem += npages << PAGE_CACHE_SHIFT; ++ cache_mem += sbi->n_orphans * sizeof(struct orphan_inode_entry); ++ cache_mem += sbi->n_dirty_dirs * sizeof(struct dir_inode_entry); ++ ++ buf += sprintf(buf, "%u KB = static: %u + cached: %u\n", ++ (base_mem + cache_mem) >> 10, ++ base_mem >> 10, ++ cache_mem >> 10); ++ mutex_unlock(&si->stat_list); ++ } ++ return buf - page; ++} ++ ++static int init_stats(struct f2fs_sb_info *sbi) ++{ ++ struct f2fs_stat_info *si; ++ struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); ++ struct f2fs_gc_info *gc_i = sbi->gc_info; ++ ++ gc_i->stat_info = kzalloc(sizeof(struct f2fs_stat_info), ++ GFP_KERNEL); ++ if (!gc_i->stat_info) ++ return -ENOMEM; ++ si = gc_i->stat_info; ++ mutex_init(&si->stat_list); ++ list_add_tail(&gc_i->stat_list, &f2fs_stat_list); ++ ++ si->all_area_segs = le32_to_cpu(raw_super->segment_count); ++ si->sit_area_segs = le32_to_cpu(raw_super->segment_count_sit); ++ si->nat_area_segs = le32_to_cpu(raw_super->segment_count_nat); ++ si->ssa_area_segs = le32_to_cpu(raw_super->segment_count_ssa); ++ si->main_area_segs = le32_to_cpu(raw_super->segment_count_main); ++ si->main_area_sections = le32_to_cpu(raw_super->section_count); ++ si->main_area_zones = si->main_area_sections / ++ le32_to_cpu(raw_super->secs_per_zone); ++ si->sbi = sbi; ++ return 0; ++} ++ ++void f2fs_destroy_gci_stats(struct f2fs_gc_info *gc_i) ++{ ++ struct f2fs_stat_info *si = gc_i->stat_info; ++ ++ list_del(&gc_i->stat_list); ++ mutex_lock(&si->stat_list); ++ si->sbi = NULL; ++ mutex_unlock(&si->stat_list); ++ kfree(gc_i->stat_info); ++} ++ ++int f2fs_stat_init(struct super_block *sb, struct f2fs_sb_info *sbi) ++{ ++ struct proc_dir_entry *entry; ++ int retval; ++ ++ if (!f2fs_proc_root) ++ f2fs_proc_root = proc_mkdir("fs/f2fs", NULL); ++ ++ sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); ++ ++ retval = init_stats(sbi); ++ if (retval) ++ return retval; ++ ++ entry = create_proc_entry("f2fs_stat", 0, sbi->s_proc); ++ if (!entry) ++ return -ENOMEM; ++ entry->read_proc = f2fs_read_gc; ++ entry->write_proc = NULL; ++ ++ entry = create_proc_entry("f2fs_sit_stat", 0, sbi->s_proc); ++ if (!entry) { ++ remove_proc_entry("f2fs_stat", sbi->s_proc); ++ return -ENOMEM; ++ } ++ entry->read_proc = f2fs_read_sit; ++ entry->write_proc = NULL; ++ entry = create_proc_entry("f2fs_mem_stat", 0, sbi->s_proc); ++ if (!entry) { ++ remove_proc_entry("f2fs_sit_stat", sbi->s_proc); ++ remove_proc_entry("f2fs_stat", sbi->s_proc); ++ return -ENOMEM; ++ } ++ entry->read_proc = f2fs_read_mem; ++ entry->write_proc = NULL; ++ return 0; ++} ++ ++void f2fs_stat_exit(struct super_block *sb, struct f2fs_sb_info *sbi) ++{ ++ if (sbi->s_proc) { ++ remove_proc_entry("f2fs_stat", sbi->s_proc); ++ remove_proc_entry("f2fs_sit_stat", sbi->s_proc); ++ remove_proc_entry("f2fs_mem_stat", sbi->s_proc); ++ remove_proc_entry(sb->s_id, f2fs_proc_root); ++ } ++} ++ ++void f2fs_remove_stats(void) ++{ ++ remove_proc_entry("fs/f2fs", NULL); ++} +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +index bbe2f02..7f508b2 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -953,12 +953,6 @@ int start_gc_thread(struct f2fs_sb_info *); + void stop_gc_thread(struct f2fs_sb_info *); + block_t start_bidx_of_node(unsigned int); + int f2fs_gc(struct f2fs_sb_info *, int); +-#ifdef CONFIG_F2FS_STAT_FS +-void f2fs_update_stat(struct f2fs_sb_info *); +-void f2fs_update_gc_metric(struct f2fs_sb_info *); +-int f2fs_stat_init(struct f2fs_sb_info *); +-void f2fs_stat_exit(struct f2fs_sb_info *); +-#endif + int build_gc_manager(struct f2fs_sb_info *); + void destroy_gc_manager(struct f2fs_sb_info *); + int create_gc_caches(void); +@@ -970,6 +964,25 @@ void destroy_gc_caches(void); + void recover_fsync_data(struct f2fs_sb_info *); + bool space_for_roll_forward(struct f2fs_sb_info *); + ++/** ++ * debug.c ++ */ ++#ifdef CONFIG_F2FS_STAT_FS ++void f2fs_update_stat(struct f2fs_sb_info *); ++int f2fs_stat_init(struct super_block *sb, struct f2fs_sb_info *); ++void f2fs_stat_exit(struct super_block *sb, struct f2fs_sb_info *); ++void f2fs_destroy_gci_stats(struct f2fs_gc_info *gc_i); ++void f2fs_remove_stats(void); ++#else ++static inline void f2fs_update_stat(struct f2fs_sb_info *sbi) { } ++static inline int f2fs_stat_init(struct super_block *sb, ++ struct f2fs_sb_info *sbi) { return 0; } ++static inline void f2fs_stat_exit(struct super_block *sb, ++ struct f2fs_sb_info *sbi) { } ++static inline void f2fs_destroy_gci_stats(struct f2fs_gc_info *gc_i) { } ++static inline void f2fs_remove_stats(void) { } ++#endif ++ + extern const struct file_operations f2fs_dir_operations; + extern const struct file_operations f2fs_file_operations; + extern const struct inode_operations f2fs_file_inode_operations; +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index 753b05e..cfdbd2c 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -24,7 +24,6 @@ + #include "segment.h" + #include "gc.h" + +-static LIST_HEAD(f2fs_stat_list); + static struct kmem_cache *winode_slab; + + static int gc_thread_func(void *data) +@@ -727,350 +726,10 @@ stop: + return gc_status; + } + +-#ifdef CONFIG_F2FS_STAT_FS +-void f2fs_update_stat(struct f2fs_sb_info *sbi) +-{ +- struct f2fs_gc_info *gc_i = sbi->gc_info; +- struct f2fs_stat_info *si = gc_i->stat_info; +- int i; +- +- /* valid check of the segment numbers */ +- si->hit_ext = sbi->read_hit_ext; +- si->total_ext = sbi->total_hit_ext; +- si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES); +- si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS); +- si->ndirty_dirs = sbi->n_dirty_dirs; +- si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META); +- si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg; +- si->rsvd_segs = reserved_segments(sbi); +- si->overp_segs = overprovision_segments(sbi); +- si->valid_count = valid_user_blocks(sbi); +- si->valid_node_count = valid_node_count(sbi); +- si->valid_inode_count = valid_inode_count(sbi); +- si->utilization = utilization(sbi); +- +- si->free_segs = free_segments(sbi); +- si->free_secs = free_sections(sbi); +- si->prefree_count = prefree_segments(sbi); +- si->dirty_count = dirty_segments(sbi); +- si->node_pages = sbi->node_inode->i_mapping->nrpages; +- si->meta_pages = sbi->meta_inode->i_mapping->nrpages; +- si->nats = NM_I(sbi)->nat_cnt; +- si->sits = SIT_I(sbi)->dirty_sentries; +- si->fnids = NM_I(sbi)->fcnt; +- si->bg_gc = sbi->bg_gc; +- si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg) +- * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg) +- / 2; +- si->util_valid = (int)(written_block_count(sbi) >> +- sbi->log_blocks_per_seg) +- * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg) +- / 2; +- si->util_invalid = 50 - si->util_free - si->util_valid; +- for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_NODE; i++) { +- struct curseg_info *curseg = CURSEG_I(sbi, i); +- si->curseg[i] = curseg->segno; +- si->cursec[i] = curseg->segno / sbi->segs_per_sec; +- si->curzone[i] = si->cursec[i] / sbi->secs_per_zone; +- } +- +- for (i = 0; i < 2; i++) { +- si->segment_count[i] = sbi->segment_count[i]; +- si->block_count[i] = sbi->block_count[i]; +- } +-} +- +-/** +- * This function calculates BDF of every segments +- */ +-void f2fs_update_gc_metric(struct f2fs_sb_info *sbi) +-{ +- struct f2fs_gc_info *gc_i = sbi->gc_info; +- struct f2fs_stat_info *si = gc_i->stat_info; +- unsigned int blks_per_sec, hblks_per_sec, total_vblocks, bimodal, dist; +- struct sit_info *sit_i = SIT_I(sbi); +- unsigned int segno, vblocks; +- int ndirty = 0; +- +- bimodal = 0; +- total_vblocks = 0; +- blks_per_sec = sbi->segs_per_sec * (1 << sbi->log_blocks_per_seg); +- hblks_per_sec = blks_per_sec / 2; +- mutex_lock(&sit_i->sentry_lock); +- for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) { +- vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec); +- dist = abs(vblocks - hblks_per_sec); +- bimodal += dist * dist; +- +- if (vblocks > 0 && vblocks < blks_per_sec) { +- total_vblocks += vblocks; +- ndirty++; +- } +- } +- mutex_unlock(&sit_i->sentry_lock); +- dist = sbi->total_sections * hblks_per_sec * hblks_per_sec / 100; +- si->bimodal = bimodal / dist; +- if (si->dirty_count) +- si->avg_vblocks = total_vblocks / ndirty; +- else +- si->avg_vblocks = 0; +-} +- +-static int f2fs_read_gc(char *page, char **start, off_t off, +- int count, int *eof, void *data) +-{ +- struct f2fs_gc_info *gc_i, *next; +- struct f2fs_stat_info *si; +- char *buf = page; +- int i = 0; +- +- list_for_each_entry_safe(gc_i, next, &f2fs_stat_list, stat_list) { +- int j; +- si = gc_i->stat_info; +- +- mutex_lock(&si->stat_list); +- if (!si->sbi) { +- mutex_unlock(&si->stat_list); +- continue; +- } +- f2fs_update_stat(si->sbi); +- +- buf += sprintf(buf, "=====[ partition info. #%d ]=====\n", i++); +- buf += sprintf(buf, "[SB: 1] [CP: 2] [NAT: %d] [SIT: %d] ", +- si->nat_area_segs, si->sit_area_segs); +- buf += sprintf(buf, "[SSA: %d] [MAIN: %d", +- si->ssa_area_segs, si->main_area_segs); +- buf += sprintf(buf, "(OverProv:%d Resv:%d)]\n\n", +- si->overp_segs, si->rsvd_segs); +- buf += sprintf(buf, "Utilization: %d%% (%d valid blocks)\n", +- si->utilization, si->valid_count); +- buf += sprintf(buf, " - Node: %u (Inode: %u, ", +- si->valid_node_count, si->valid_inode_count); +- buf += sprintf(buf, "Other: %u)\n - Data: %u\n", +- si->valid_node_count - si->valid_inode_count, +- si->valid_count - si->valid_node_count); +- buf += sprintf(buf, "\nMain area: %d segs, %d secs %d zones\n", +- si->main_area_segs, si->main_area_sections, +- si->main_area_zones); +- buf += sprintf(buf, " - COLD data: %d, %d, %d\n", +- si->curseg[CURSEG_COLD_DATA], +- si->cursec[CURSEG_COLD_DATA], +- si->curzone[CURSEG_COLD_DATA]); +- buf += sprintf(buf, " - WARM data: %d, %d, %d\n", +- si->curseg[CURSEG_WARM_DATA], +- si->cursec[CURSEG_WARM_DATA], +- si->curzone[CURSEG_WARM_DATA]); +- buf += sprintf(buf, " - HOT data: %d, %d, %d\n", +- si->curseg[CURSEG_HOT_DATA], +- si->cursec[CURSEG_HOT_DATA], +- si->curzone[CURSEG_HOT_DATA]); +- buf += sprintf(buf, " - Dir dnode: %d, %d, %d\n", +- si->curseg[CURSEG_HOT_NODE], +- si->cursec[CURSEG_HOT_NODE], +- si->curzone[CURSEG_HOT_NODE]); +- buf += sprintf(buf, " - File dnode: %d, %d, %d\n", +- si->curseg[CURSEG_WARM_NODE], +- si->cursec[CURSEG_WARM_NODE], +- si->curzone[CURSEG_WARM_NODE]); +- buf += sprintf(buf, " - Indir nodes: %d, %d, %d\n", +- si->curseg[CURSEG_COLD_NODE], +- si->cursec[CURSEG_COLD_NODE], +- si->curzone[CURSEG_COLD_NODE]); +- buf += sprintf(buf, "\n - Valid: %d\n - Dirty: %d\n", +- si->main_area_segs - si->dirty_count - +- si->prefree_count - si->free_segs, +- si->dirty_count); +- buf += sprintf(buf, " - Prefree: %d\n - Free: %d (%d)\n\n", +- si->prefree_count, +- si->free_segs, +- si->free_secs); +- buf += sprintf(buf, "GC calls: %d (BG: %d)\n", +- si->call_count, si->bg_gc); +- buf += sprintf(buf, " - data segments : %d\n", si->data_segs); +- buf += sprintf(buf, " - node segments : %d\n", si->node_segs); +- buf += sprintf(buf, "Try to move %d blocks\n", si->tot_blks); +- buf += sprintf(buf, " - data blocks : %d\n", si->data_blks); +- buf += sprintf(buf, " - node blocks : %d\n", si->node_blks); +- buf += sprintf(buf, "\nExtent Hit Ratio: %d / %d\n", +- si->hit_ext, si->total_ext); +- buf += sprintf(buf, "\nBalancing F2FS Async:\n"); +- buf += sprintf(buf, " - nodes %4d in %4d\n", +- si->ndirty_node, si->node_pages); +- buf += sprintf(buf, " - dents %4d in dirs:%4d\n", +- si->ndirty_dent, si->ndirty_dirs); +- buf += sprintf(buf, " - meta %4d in %4d\n", +- si->ndirty_meta, si->meta_pages); +- buf += sprintf(buf, " - NATs %5d > %lu\n", +- si->nats, NM_WOUT_THRESHOLD); +- buf += sprintf(buf, " - SITs: %5d\n - free_nids: %5d\n", +- si->sits, si->fnids); +- buf += sprintf(buf, "\nDistribution of User Blocks:"); +- buf += sprintf(buf, " [ valid | invalid | free ]\n"); +- buf += sprintf(buf, " ["); +- for (j = 0; j < si->util_valid; j++) +- buf += sprintf(buf, "-"); +- buf += sprintf(buf, "|"); +- for (j = 0; j < si->util_invalid; j++) +- buf += sprintf(buf, "-"); +- buf += sprintf(buf, "|"); +- for (j = 0; j < si->util_free; j++) +- buf += sprintf(buf, "-"); +- buf += sprintf(buf, "]\n\n"); +- buf += sprintf(buf, "SSR: %u blocks in %u segments\n", +- si->block_count[SSR], si->segment_count[SSR]); +- buf += sprintf(buf, "LFS: %u blocks in %u segments\n", +- si->block_count[LFS], si->segment_count[LFS]); +- mutex_unlock(&si->stat_list); +- } +- return buf - page; +-} +- +-static int f2fs_read_sit(char *page, char **start, off_t off, +- int count, int *eof, void *data) +-{ +- struct f2fs_gc_info *gc_i, *next; +- struct f2fs_stat_info *si; +- char *buf = page; +- +- list_for_each_entry_safe(gc_i, next, &f2fs_stat_list, stat_list) { +- si = gc_i->stat_info; +- +- mutex_lock(&si->stat_list); +- if (!si->sbi) { +- mutex_unlock(&si->stat_list); +- continue; +- } +- f2fs_update_gc_metric(si->sbi); +- +- buf += sprintf(buf, "BDF: %u, avg. vblocks: %u\n", +- si->bimodal, si->avg_vblocks); +- mutex_unlock(&si->stat_list); +- } +- return buf - page; +-} +- +-static int f2fs_read_mem(char *page, char **start, off_t off, +- int count, int *eof, void *data) +-{ +- struct f2fs_gc_info *gc_i, *next; +- struct f2fs_stat_info *si; +- char *buf = page; +- +- list_for_each_entry_safe(gc_i, next, &f2fs_stat_list, stat_list) { +- struct f2fs_sb_info *sbi = gc_i->stat_info->sbi; +- unsigned npages; +- unsigned base_mem = 0, cache_mem = 0; +- +- si = gc_i->stat_info; +- mutex_lock(&si->stat_list); +- if (!si->sbi) { +- mutex_unlock(&si->stat_list); +- continue; +- } +- base_mem += sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize; +- base_mem += 2 * sizeof(struct f2fs_inode_info); +- base_mem += sizeof(*sbi->ckpt); +- +- /* build sm */ +- base_mem += sizeof(struct f2fs_sm_info); +- +- /* build sit */ +- base_mem += sizeof(struct sit_info); +- base_mem += TOTAL_SEGS(sbi) * sizeof(struct seg_entry); +- base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi)); +- base_mem += 2 * SIT_VBLOCK_MAP_SIZE * TOTAL_SEGS(sbi); +- if (sbi->segs_per_sec > 1) +- base_mem += sbi->total_sections * +- sizeof(struct sec_entry); +- base_mem += __bitmap_size(sbi, SIT_BITMAP); +- +- /* build free segmap */ +- base_mem += sizeof(struct free_segmap_info); +- base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi)); +- base_mem += f2fs_bitmap_size(sbi->total_sections); +- +- /* build curseg */ +- base_mem += sizeof(struct curseg_info) * NR_CURSEG_TYPE; +- base_mem += PAGE_CACHE_SIZE * NR_CURSEG_TYPE; +- +- /* build dirty segmap */ +- base_mem += sizeof(struct dirty_seglist_info); +- base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(TOTAL_SEGS(sbi)); +- base_mem += 2 * f2fs_bitmap_size(TOTAL_SEGS(sbi)); +- +- /* buld nm */ +- base_mem += sizeof(struct f2fs_nm_info); +- base_mem += __bitmap_size(sbi, NAT_BITMAP); +- +- /* build gc */ +- base_mem += sizeof(struct f2fs_gc_info); +- base_mem += sizeof(struct f2fs_gc_kthread); +- +- /* free nids */ +- cache_mem += NM_I(sbi)->fcnt; +- cache_mem += NM_I(sbi)->nat_cnt; +- npages = sbi->node_inode->i_mapping->nrpages; +- cache_mem += npages << PAGE_CACHE_SHIFT; +- npages = sbi->meta_inode->i_mapping->nrpages; +- cache_mem += npages << PAGE_CACHE_SHIFT; +- cache_mem += sbi->n_orphans * sizeof(struct orphan_inode_entry); +- cache_mem += sbi->n_dirty_dirs * sizeof(struct dir_inode_entry); +- +- buf += sprintf(buf, "%u KB = static: %u + cached: %u\n", +- (base_mem + cache_mem) >> 10, +- base_mem >> 10, +- cache_mem >> 10); +- mutex_unlock(&si->stat_list); +- } +- return buf - page; +-} +- +-int f2fs_stat_init(struct f2fs_sb_info *sbi) +-{ +- struct proc_dir_entry *entry; +- +- entry = create_proc_entry("f2fs_stat", 0, sbi->s_proc); +- if (!entry) +- return -ENOMEM; +- entry->read_proc = f2fs_read_gc; +- entry->write_proc = NULL; +- +- entry = create_proc_entry("f2fs_sit_stat", 0, sbi->s_proc); +- if (!entry) { +- remove_proc_entry("f2fs_stat", sbi->s_proc); +- return -ENOMEM; +- } +- entry->read_proc = f2fs_read_sit; +- entry->write_proc = NULL; +- entry = create_proc_entry("f2fs_mem_stat", 0, sbi->s_proc); +- if (!entry) { +- remove_proc_entry("f2fs_sit_stat", sbi->s_proc); +- remove_proc_entry("f2fs_stat", sbi->s_proc); +- return -ENOMEM; +- } +- entry->read_proc = f2fs_read_mem; +- entry->write_proc = NULL; +- return 0; +-} +- +-void f2fs_stat_exit(struct f2fs_sb_info *sbi) +-{ +- if (sbi->s_proc) { +- remove_proc_entry("f2fs_stat", sbi->s_proc); +- remove_proc_entry("f2fs_sit_stat", sbi->s_proc); +- remove_proc_entry("f2fs_mem_stat", sbi->s_proc); +- } +-} +-#endif +- + int build_gc_manager(struct f2fs_sb_info *sbi) + { + struct f2fs_gc_info *gc_i; + struct f2fs_checkpoint *ckp = F2FS_CKPT(sbi); +-#ifdef CONFIG_F2FS_STAT_FS +- struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); +- struct f2fs_stat_info *si; +-#endif + + gc_i = kzalloc(sizeof(struct f2fs_gc_info), GFP_KERNEL); + if (!gc_i) +@@ -1082,44 +741,18 @@ int build_gc_manager(struct f2fs_sb_info *sbi) + + DIRTY_I(sbi)->v_ops = &default_v_ops; + +-#ifdef CONFIG_F2FS_STAT_FS +- gc_i->stat_info = kzalloc(sizeof(struct f2fs_stat_info), +- GFP_KERNEL); +- if (!gc_i->stat_info) +- return -ENOMEM; +- si = gc_i->stat_info; +- mutex_init(&si->stat_list); +- list_add_tail(&gc_i->stat_list, &f2fs_stat_list); +- +- si->all_area_segs = le32_to_cpu(raw_super->segment_count); +- si->sit_area_segs = le32_to_cpu(raw_super->segment_count_sit); +- si->nat_area_segs = le32_to_cpu(raw_super->segment_count_nat); +- si->ssa_area_segs = le32_to_cpu(raw_super->segment_count_ssa); +- si->main_area_segs = le32_to_cpu(raw_super->segment_count_main); +- si->main_area_sections = le32_to_cpu(raw_super->section_count); +- si->main_area_zones = si->main_area_sections / +- le32_to_cpu(raw_super->secs_per_zone); +- si->sbi = sbi; +-#endif + return 0; + } + + void destroy_gc_manager(struct f2fs_sb_info *sbi) + { + struct f2fs_gc_info *gc_i = sbi->gc_info; +-#ifdef CONFIG_F2FS_STAT_FS +- struct f2fs_stat_info *si = gc_i->stat_info; +-#endif ++ + if (!gc_i) + return; + +-#ifdef CONFIG_F2FS_STAT_FS +- list_del(&gc_i->stat_list); +- mutex_lock(&si->stat_list); +- si->sbi = NULL; +- mutex_unlock(&si->stat_list); +- kfree(gc_i->stat_info); +-#endif ++ f2fs_destroy_gci_stats(gc_i); ++ + sbi->gc_info = NULL; + kfree(gc_i); + } +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index 8e608a0..65feb4b 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -26,7 +26,6 @@ + #include "xattr.h" + + static struct kmem_cache *f2fs_inode_cachep; +-static struct proc_dir_entry *f2fs_proc_root; + + enum { + Opt_gc_background_off, +@@ -97,12 +96,7 @@ static void f2fs_put_super(struct super_block *sb) + { + struct f2fs_sb_info *sbi = F2FS_SB(sb); + +-#ifdef CONFIG_F2FS_STAT_FS +- if (sbi->s_proc) { +- f2fs_stat_exit(sbi); +- remove_proc_entry(sb->s_id, f2fs_proc_root); +- } +-#endif ++ f2fs_stat_exit(sb, sbi); + stop_gc_thread(sbi); + + write_checkpoint(sbi, false, true); +@@ -486,13 +480,9 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) + if (start_gc_thread(sbi)) + goto fail; + +-#ifdef CONFIG_F2FS_STAT_FS +- if (f2fs_proc_root) { +- sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); +- if (f2fs_stat_init(sbi)) +- goto fail; +- } +-#endif ++ if (f2fs_stat_init(sb, sbi)) ++ goto fail; ++ + return 0; + fail: + stop_gc_thread(sbi); +@@ -566,7 +556,6 @@ static int __init init_f2fs_fs(void) + if (register_filesystem(&f2fs_fs_type)) + return -EBUSY; + +- f2fs_proc_root = proc_mkdir("fs/f2fs", NULL); + return 0; + fail: + return -ENOMEM; +@@ -574,7 +563,7 @@ fail: + + static void __exit exit_f2fs_fs(void) + { +- remove_proc_entry("fs/f2fs", NULL); ++ f2fs_remove_stats(); + unregister_filesystem(&f2fs_fs_type); + destroy_checkpoint_caches(); + destroy_gc_caches(); diff --git a/patches/linux-3.7-rc6/0116-f2fs-move-proc-files-to-debugfs.patch b/patches/linux-3.7-rc6/0116-f2fs-move-proc-files-to-debugfs.patch new file mode 100644 index 0000000..aa87b59 --- /dev/null +++ b/patches/linux-3.7-rc6/0116-f2fs-move-proc-files-to-debugfs.patch @@ -0,0 +1,449 @@ +From 205e2ea14ae2f19cae72407e023d736c5c781027 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Tue, 23 Oct 2012 19:20:28 +0000 +Subject: [PATCH] f2fs: move proc files to debugfs + +This moves all of the f2fs debugging files into debugfs. The files are +located in /sys/kernel/debug/f2fs/ + +Note, I think we are generating all of the same information in each of +the files for every unique f2fs filesystem in the machine. This copies +the functionality that was present in the proc files, but this should be +fixed up in the future. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + fs/f2fs/Kconfig | 8 +- + fs/f2fs/debug.c | 294 ++++++++++++++++++++++++++++++------------------------- + fs/f2fs/f2fs.h | 2 +- + 3 files changed, 165 insertions(+), 139 deletions(-) + +diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig +index 8821c6a..dd181c6 100644 +--- a/fs/f2fs/Kconfig ++++ b/fs/f2fs/Kconfig +@@ -16,18 +16,18 @@ config F2FS_FS + + config F2FS_STAT_FS + bool "F2FS Status Information" +- depends on F2FS_FS ++ depends on F2FS_FS && DEBUG_FS + default y + help +- /proc/fs/f2fs/ contains information about partitions mounted as f2fs. ++ /sys/kernel/debug/f2fs/ contains information about partitions mounted as f2fs. + For each partition, a corresponding directory, named as its device +- name, is provided with the following proc entries. ++ name, is provided with the following files: + + f2fs_stat major file system information managed by f2fs currently + f2fs_sit_stat average SIT information about whole segments + f2fs_mem_stat current memory footprint consumed by f2fs + +- e.g., in /proc/fs/f2fs/sdb1/ ++ e.g., in /sys/kernel/debug/f2fs/sdb1/ + + config F2FS_FS_XATTR + bool "F2FS extended attributes" +diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c +index 0145b02..ec5beba 100644 +--- a/fs/f2fs/debug.c ++++ b/fs/f2fs/debug.c +@@ -16,6 +16,8 @@ + #include <linux/proc_fs.h> + #include <linux/f2fs_fs.h> + #include <linux/blkdev.h> ++#include <linux/debugfs.h> ++#include <linux/seq_file.h> + + #include "f2fs.h" + #include "node.h" +@@ -23,7 +25,7 @@ + #include "gc.h" + + static LIST_HEAD(f2fs_stat_list); +-static struct proc_dir_entry *f2fs_proc_root; ++static struct dentry *debugfs_root; + + + void f2fs_update_stat(struct f2fs_sb_info *sbi) +@@ -114,16 +116,14 @@ static void f2fs_update_gc_metric(struct f2fs_sb_info *sbi) + si->avg_vblocks = 0; + } + +-static int f2fs_read_gc(char *page, char **start, off_t off, +- int count, int *eof, void *data) ++static int stat_show(struct seq_file *s, void *v) + { + struct f2fs_gc_info *gc_i, *next; + struct f2fs_stat_info *si; +- char *buf = page; + int i = 0; ++ int j; + + list_for_each_entry_safe(gc_i, next, &f2fs_stat_list, stat_list) { +- int j; + si = gc_i->stat_info; + + mutex_lock(&si->stat_list); +@@ -133,102 +133,111 @@ static int f2fs_read_gc(char *page, char **start, off_t off, + } + f2fs_update_stat(si->sbi); + +- buf += sprintf(buf, "=====[ partition info. #%d ]=====\n", i++); +- buf += sprintf(buf, "[SB: 1] [CP: 2] [NAT: %d] [SIT: %d] ", +- si->nat_area_segs, si->sit_area_segs); +- buf += sprintf(buf, "[SSA: %d] [MAIN: %d", +- si->ssa_area_segs, si->main_area_segs); +- buf += sprintf(buf, "(OverProv:%d Resv:%d)]\n\n", +- si->overp_segs, si->rsvd_segs); +- buf += sprintf(buf, "Utilization: %d%% (%d valid blocks)\n", +- si->utilization, si->valid_count); +- buf += sprintf(buf, " - Node: %u (Inode: %u, ", +- si->valid_node_count, si->valid_inode_count); +- buf += sprintf(buf, "Other: %u)\n - Data: %u\n", +- si->valid_node_count - si->valid_inode_count, +- si->valid_count - si->valid_node_count); +- buf += sprintf(buf, "\nMain area: %d segs, %d secs %d zones\n", +- si->main_area_segs, si->main_area_sections, +- si->main_area_zones); +- buf += sprintf(buf, " - COLD data: %d, %d, %d\n", +- si->curseg[CURSEG_COLD_DATA], +- si->cursec[CURSEG_COLD_DATA], +- si->curzone[CURSEG_COLD_DATA]); +- buf += sprintf(buf, " - WARM data: %d, %d, %d\n", +- si->curseg[CURSEG_WARM_DATA], +- si->cursec[CURSEG_WARM_DATA], +- si->curzone[CURSEG_WARM_DATA]); +- buf += sprintf(buf, " - HOT data: %d, %d, %d\n", +- si->curseg[CURSEG_HOT_DATA], +- si->cursec[CURSEG_HOT_DATA], +- si->curzone[CURSEG_HOT_DATA]); +- buf += sprintf(buf, " - Dir dnode: %d, %d, %d\n", +- si->curseg[CURSEG_HOT_NODE], +- si->cursec[CURSEG_HOT_NODE], +- si->curzone[CURSEG_HOT_NODE]); +- buf += sprintf(buf, " - File dnode: %d, %d, %d\n", +- si->curseg[CURSEG_WARM_NODE], +- si->cursec[CURSEG_WARM_NODE], +- si->curzone[CURSEG_WARM_NODE]); +- buf += sprintf(buf, " - Indir nodes: %d, %d, %d\n", +- si->curseg[CURSEG_COLD_NODE], +- si->cursec[CURSEG_COLD_NODE], +- si->curzone[CURSEG_COLD_NODE]); +- buf += sprintf(buf, "\n - Valid: %d\n - Dirty: %d\n", +- si->main_area_segs - si->dirty_count - +- si->prefree_count - si->free_segs, +- si->dirty_count); +- buf += sprintf(buf, " - Prefree: %d\n - Free: %d (%d)\n\n", +- si->prefree_count, +- si->free_segs, +- si->free_secs); +- buf += sprintf(buf, "GC calls: %d (BG: %d)\n", +- si->call_count, si->bg_gc); +- buf += sprintf(buf, " - data segments : %d\n", si->data_segs); +- buf += sprintf(buf, " - node segments : %d\n", si->node_segs); +- buf += sprintf(buf, "Try to move %d blocks\n", si->tot_blks); +- buf += sprintf(buf, " - data blocks : %d\n", si->data_blks); +- buf += sprintf(buf, " - node blocks : %d\n", si->node_blks); +- buf += sprintf(buf, "\nExtent Hit Ratio: %d / %d\n", +- si->hit_ext, si->total_ext); +- buf += sprintf(buf, "\nBalancing F2FS Async:\n"); +- buf += sprintf(buf, " - nodes %4d in %4d\n", +- si->ndirty_node, si->node_pages); +- buf += sprintf(buf, " - dents %4d in dirs:%4d\n", +- si->ndirty_dent, si->ndirty_dirs); +- buf += sprintf(buf, " - meta %4d in %4d\n", +- si->ndirty_meta, si->meta_pages); +- buf += sprintf(buf, " - NATs %5d > %lu\n", +- si->nats, NM_WOUT_THRESHOLD); +- buf += sprintf(buf, " - SITs: %5d\n - free_nids: %5d\n", +- si->sits, si->fnids); +- buf += sprintf(buf, "\nDistribution of User Blocks:"); +- buf += sprintf(buf, " [ valid | invalid | free ]\n"); +- buf += sprintf(buf, " ["); ++ seq_printf(s, "=====[ partition info. #%d ]=====\n", i++); ++ seq_printf(s, "=====[ partition info. #%d ]=====\n", i++); ++ seq_printf(s, "[SB: 1] [CP: 2] [NAT: %d] [SIT: %d] ", ++ si->nat_area_segs, si->sit_area_segs); ++ seq_printf(s, "[SSA: %d] [MAIN: %d", ++ si->ssa_area_segs, si->main_area_segs); ++ seq_printf(s, "(OverProv:%d Resv:%d)]\n\n", ++ si->overp_segs, si->rsvd_segs); ++ seq_printf(s, "Utilization: %d%% (%d valid blocks)\n", ++ si->utilization, si->valid_count); ++ seq_printf(s, " - Node: %u (Inode: %u, ", ++ si->valid_node_count, si->valid_inode_count); ++ seq_printf(s, "Other: %u)\n - Data: %u\n", ++ si->valid_node_count - si->valid_inode_count, ++ si->valid_count - si->valid_node_count); ++ seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n", ++ si->main_area_segs, si->main_area_sections, ++ si->main_area_zones); ++ seq_printf(s, " - COLD data: %d, %d, %d\n", ++ si->curseg[CURSEG_COLD_DATA], ++ si->cursec[CURSEG_COLD_DATA], ++ si->curzone[CURSEG_COLD_DATA]); ++ seq_printf(s, " - WARM data: %d, %d, %d\n", ++ si->curseg[CURSEG_WARM_DATA], ++ si->cursec[CURSEG_WARM_DATA], ++ si->curzone[CURSEG_WARM_DATA]); ++ seq_printf(s, " - HOT data: %d, %d, %d\n", ++ si->curseg[CURSEG_HOT_DATA], ++ si->cursec[CURSEG_HOT_DATA], ++ si->curzone[CURSEG_HOT_DATA]); ++ seq_printf(s, " - Dir dnode: %d, %d, %d\n", ++ si->curseg[CURSEG_HOT_NODE], ++ si->cursec[CURSEG_HOT_NODE], ++ si->curzone[CURSEG_HOT_NODE]); ++ seq_printf(s, " - File dnode: %d, %d, %d\n", ++ si->curseg[CURSEG_WARM_NODE], ++ si->cursec[CURSEG_WARM_NODE], ++ si->curzone[CURSEG_WARM_NODE]); ++ seq_printf(s, " - Indir nodes: %d, %d, %d\n", ++ si->curseg[CURSEG_COLD_NODE], ++ si->cursec[CURSEG_COLD_NODE], ++ si->curzone[CURSEG_COLD_NODE]); ++ seq_printf(s, "\n - Valid: %d\n - Dirty: %d\n", ++ si->main_area_segs - si->dirty_count - ++ si->prefree_count - si->free_segs, ++ si->dirty_count); ++ seq_printf(s, " - Prefree: %d\n - Free: %d (%d)\n\n", ++ si->prefree_count, si->free_segs, si->free_secs); ++ seq_printf(s, "GC calls: %d (BG: %d)\n", ++ si->call_count, si->bg_gc); ++ seq_printf(s, " - data segments : %d\n", si->data_segs); ++ seq_printf(s, " - node segments : %d\n", si->node_segs); ++ seq_printf(s, "Try to move %d blocks\n", si->tot_blks); ++ seq_printf(s, " - data blocks : %d\n", si->data_blks); ++ seq_printf(s, " - node blocks : %d\n", si->node_blks); ++ seq_printf(s, "\nExtent Hit Ratio: %d / %d\n", ++ si->hit_ext, si->total_ext); ++ seq_printf(s, "\nBalancing F2FS Async:\n"); ++ seq_printf(s, " - nodes %4d in %4d\n", ++ si->ndirty_node, si->node_pages); ++ seq_printf(s, " - dents %4d in dirs:%4d\n", ++ si->ndirty_dent, si->ndirty_dirs); ++ seq_printf(s, " - meta %4d in %4d\n", ++ si->ndirty_meta, si->meta_pages); ++ seq_printf(s, " - NATs %5d > %lu\n", ++ si->nats, NM_WOUT_THRESHOLD); ++ seq_printf(s, " - SITs: %5d\n - free_nids: %5d\n", ++ si->sits, si->fnids); ++ seq_printf(s, "\nDistribution of User Blocks:"); ++ seq_printf(s, " [ valid | invalid | free ]\n"); ++ seq_printf(s, " ["); + for (j = 0; j < si->util_valid; j++) +- buf += sprintf(buf, "-"); +- buf += sprintf(buf, "|"); ++ seq_printf(s, "-"); ++ seq_printf(s, "|"); + for (j = 0; j < si->util_invalid; j++) +- buf += sprintf(buf, "-"); +- buf += sprintf(buf, "|"); ++ seq_printf(s, "-"); ++ seq_printf(s, "|"); + for (j = 0; j < si->util_free; j++) +- buf += sprintf(buf, "-"); +- buf += sprintf(buf, "]\n\n"); +- buf += sprintf(buf, "SSR: %u blocks in %u segments\n", +- si->block_count[SSR], si->segment_count[SSR]); +- buf += sprintf(buf, "LFS: %u blocks in %u segments\n", +- si->block_count[LFS], si->segment_count[LFS]); ++ seq_printf(s, "-"); ++ seq_printf(s, "]\n\n"); ++ seq_printf(s, "SSR: %u blocks in %u segments\n", ++ si->block_count[SSR], si->segment_count[SSR]); ++ seq_printf(s, "LFS: %u blocks in %u segments\n", ++ si->block_count[LFS], si->segment_count[LFS]); + mutex_unlock(&si->stat_list); + } +- return buf - page; ++ return 0; + } + +-static int f2fs_read_sit(char *page, char **start, off_t off, +- int count, int *eof, void *data) ++static int stat_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, stat_show, inode->i_private); ++} ++ ++static const struct file_operations stat_fops = { ++ .open = stat_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int sit_show(struct seq_file *s, void *v) + { + struct f2fs_gc_info *gc_i, *next; + struct f2fs_stat_info *si; +- char *buf = page; + + list_for_each_entry_safe(gc_i, next, &f2fs_stat_list, stat_list) { + si = gc_i->stat_info; +@@ -240,19 +249,29 @@ static int f2fs_read_sit(char *page, char **start, off_t off, + } + f2fs_update_gc_metric(si->sbi); + +- buf += sprintf(buf, "BDF: %u, avg. vblocks: %u\n", +- si->bimodal, si->avg_vblocks); ++ seq_printf(s, "BDF: %u, avg. vblocks: %u\n", ++ si->bimodal, si->avg_vblocks); + mutex_unlock(&si->stat_list); + } +- return buf - page; ++ return 0; ++} ++ ++static int sit_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, sit_show, inode->i_private); + } + +-static int f2fs_read_mem(char *page, char **start, off_t off, +- int count, int *eof, void *data) ++static const struct file_operations sit_fops = { ++ .open = sit_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int mem_show(struct seq_file *s, void *v) + { + struct f2fs_gc_info *gc_i, *next; + struct f2fs_stat_info *si; +- char *buf = page; + + list_for_each_entry_safe(gc_i, next, &f2fs_stat_list, stat_list) { + struct f2fs_sb_info *sbi = gc_i->stat_info->sbi; +@@ -314,15 +333,27 @@ static int f2fs_read_mem(char *page, char **start, off_t off, + cache_mem += sbi->n_orphans * sizeof(struct orphan_inode_entry); + cache_mem += sbi->n_dirty_dirs * sizeof(struct dir_inode_entry); + +- buf += sprintf(buf, "%u KB = static: %u + cached: %u\n", +- (base_mem + cache_mem) >> 10, +- base_mem >> 10, +- cache_mem >> 10); ++ seq_printf(s, "%u KB = static: %u + cached: %u\n", ++ (base_mem + cache_mem) >> 10, ++ base_mem >> 10, cache_mem >> 10); + mutex_unlock(&si->stat_list); + } +- return buf - page; ++ return 0; ++} ++ ++static int mem_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mem_show, inode->i_private); + } + ++static const struct file_operations mem_fops = { ++ .open = mem_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++ + static int init_stats(struct f2fs_sb_info *sbi) + { + struct f2fs_stat_info *si; +@@ -362,53 +393,48 @@ void f2fs_destroy_gci_stats(struct f2fs_gc_info *gc_i) + + int f2fs_stat_init(struct super_block *sb, struct f2fs_sb_info *sbi) + { +- struct proc_dir_entry *entry; + int retval; + +- if (!f2fs_proc_root) +- f2fs_proc_root = proc_mkdir("fs/f2fs", NULL); +- +- sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); +- + retval = init_stats(sbi); + if (retval) + return retval; + +- entry = create_proc_entry("f2fs_stat", 0, sbi->s_proc); +- if (!entry) +- return -ENOMEM; +- entry->read_proc = f2fs_read_gc; +- entry->write_proc = NULL; ++ if (!debugfs_root) ++ debugfs_root = debugfs_create_dir("f2fs", NULL); ++ ++ sbi->s_debug = debugfs_create_dir(sb->s_id, debugfs_root); ++ if (!sbi->s_debug) ++ return -EINVAL; ++ ++ if (!debugfs_create_file("f2fs_stat", S_IRUGO, sbi->s_debug, ++ NULL, &stat_fops)) ++ goto failed; ++ ++ if (!debugfs_create_file("f2fs_sit_stat", S_IRUGO, sbi->s_debug, ++ NULL, &sit_fops)) ++ goto failed; ++ ++ if (!debugfs_create_file("f2fs_mem_stat", S_IRUGO, sbi->s_debug, ++ NULL, &mem_fops)) ++ goto failed; + +- entry = create_proc_entry("f2fs_sit_stat", 0, sbi->s_proc); +- if (!entry) { +- remove_proc_entry("f2fs_stat", sbi->s_proc); +- return -ENOMEM; +- } +- entry->read_proc = f2fs_read_sit; +- entry->write_proc = NULL; +- entry = create_proc_entry("f2fs_mem_stat", 0, sbi->s_proc); +- if (!entry) { +- remove_proc_entry("f2fs_sit_stat", sbi->s_proc); +- remove_proc_entry("f2fs_stat", sbi->s_proc); +- return -ENOMEM; +- } +- entry->read_proc = f2fs_read_mem; +- entry->write_proc = NULL; + return 0; ++failed: ++ debugfs_remove_recursive(sbi->s_debug); ++ sbi->s_debug = NULL; ++ return -EINVAL; + } + + void f2fs_stat_exit(struct super_block *sb, struct f2fs_sb_info *sbi) + { +- if (sbi->s_proc) { +- remove_proc_entry("f2fs_stat", sbi->s_proc); +- remove_proc_entry("f2fs_sit_stat", sbi->s_proc); +- remove_proc_entry("f2fs_mem_stat", sbi->s_proc); +- remove_proc_entry(sb->s_id, f2fs_proc_root); ++ if (sbi->s_debug) { ++ debugfs_remove_recursive(sbi->s_debug); ++ sbi->s_debug = NULL; + } + } + + void f2fs_remove_stats(void) + { +- remove_proc_entry("fs/f2fs", NULL); ++ debugfs_remove_recursive(debugfs_root); ++ debugfs_root = NULL; + } +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +index 7f508b2..dc8045c 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -379,7 +379,7 @@ struct f2fs_sb_info { + int rr_flush; + + /* related to GC */ +- struct proc_dir_entry *s_proc; ++ struct dentry *s_debug; + struct f2fs_gc_info *gc_info; /* Garbage Collector + information */ + struct mutex gc_mutex; /* mutex for GC */ diff --git a/patches/linux-3.7-rc6/0117-f2fs-compile-fix.patch b/patches/linux-3.7-rc6/0117-f2fs-compile-fix.patch new file mode 100644 index 0000000..d93a4ea --- /dev/null +++ b/patches/linux-3.7-rc6/0117-f2fs-compile-fix.patch @@ -0,0 +1,22 @@ +From 7988df6c5e0a9d19cbe68831a9e1ce11e85e35ad Mon Sep 17 00:00:00 2001 +From: Koen Kooi <koen@dominion.thruhere.net> +Date: Wed, 24 Oct 2012 11:34:54 +0200 +Subject: [PATCH] f2fs: compile fix + +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + fs/f2fs/segment.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c +index 57d0931..5bab838 100644 +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -12,6 +12,7 @@ + #include <linux/f2fs_fs.h> + #include <linux/bio.h> + #include <linux/blkdev.h> ++#include <linux/vmalloc.h> + + #include "f2fs.h" + #include "segment.h" diff --git a/patches/linux-3.7-rc6/0119-i2c-EEPROM-Export-memory-accessor.patch b/patches/linux-3.7-rc6/0119-i2c-EEPROM-Export-memory-accessor.patch new file mode 100644 index 0000000..dc19a4a --- /dev/null +++ b/patches/linux-3.7-rc6/0119-i2c-EEPROM-Export-memory-accessor.patch @@ -0,0 +1,89 @@ +From d13ed856c7be4d21b920a440f1784e3c13752954 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Sat, 13 Oct 2012 16:06:48 +0300 +Subject: [PATCH] i2c-EEPROM: Export memory accessor + +Various platforms need access to the EEPROM in other +places besides their platform registration callbacks. +Export the memory accessor to the i2c_client and implement +it for the at24 driver. +--- + drivers/misc/eeprom/at24.c | 5 +++++ + include/linux/i2c.h | 24 ++++++++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c +index ab1ad41..4f88ae65 100644 +--- a/drivers/misc/eeprom/at24.c ++++ b/drivers/misc/eeprom/at24.c +@@ -609,6 +609,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) + + at24->client[0] = client; + ++ /* export accessor */ ++ client->macc = &at24->macc; ++ + /* use dummy devices for multiple-address chips */ + for (i = 1; i < num_addresses; i++) { + at24->client[i] = i2c_new_dummy(client->adapter, +@@ -619,6 +622,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) + err = -EADDRINUSE; + goto err_clients; + } ++ at24->client[i]->macc = &at24->macc; + } + + err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin); +@@ -637,6 +641,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) + I2C_SMBUS_WORD_DATA ? "word" : "byte"); + } + ++ + /* export data to kernel code */ + if (chip.setup) + chip.setup(&at24->macc, chip.context); +diff --git a/include/linux/i2c.h b/include/linux/i2c.h +index 800de22..e20ad4e 100644 +--- a/include/linux/i2c.h ++++ b/include/linux/i2c.h +@@ -33,6 +33,7 @@ + #include <linux/of.h> /* for struct device_node */ + #include <linux/swab.h> /* for swab16 */ + #include <uapi/linux/i2c.h> ++#include <linux/memory.h> + + extern struct bus_type i2c_bus_type; + extern struct device_type i2c_adapter_type; +@@ -229,9 +230,32 @@ struct i2c_client { + struct device dev; /* the device structure */ + int irq; /* irq issued by device */ + struct list_head detected; ++ ++ /* export accessor */ ++ struct memory_accessor *macc; + }; + #define to_i2c_client(d) container_of(d, struct i2c_client, dev) + ++static inline ssize_t i2c_memory_read(struct i2c_client *client, char *buf, off_t offset, ++ size_t count) ++{ ++ struct memory_accessor *macc = client->macc; ++ ++ if (macc == NULL || macc->read == NULL) ++ return -ENODEV; ++ return (*client->macc->read)(macc, buf, offset, count); ++} ++ ++static inline ssize_t i2c_memory_write(struct i2c_client *client, const char *buf, off_t offset, ++ size_t count) ++{ ++ struct memory_accessor *macc = client->macc; ++ ++ if (macc == NULL || macc->write == NULL) ++ return -ENODEV; ++ return (*client->macc->write)(macc, buf, offset, count); ++} ++ + extern struct i2c_client *i2c_verify_client(struct device *dev); + extern struct i2c_adapter *i2c_verify_adapter(struct device *dev); + diff --git a/patches/linux-3.7-rc6/0120-omap-Export-omap_hwmod_lookup-omap_device_build-omap.patch b/patches/linux-3.7-rc6/0120-omap-Export-omap_hwmod_lookup-omap_device_build-omap.patch new file mode 100644 index 0000000..854ce11 --- /dev/null +++ b/patches/linux-3.7-rc6/0120-omap-Export-omap_hwmod_lookup-omap_device_build-omap.patch @@ -0,0 +1,71 @@ +From 1222463525efa67a795b293e46429f510768a2df Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Sat, 13 Oct 2012 16:34:44 +0300 +Subject: [PATCH] omap: Export + omap_hwmod_lookup/omap_device_build/omap_device_build_ss + +These functions can be used just fine by modules, there's no need not +to have them exported. +--- + arch/arm/mach-omap2/omap_hwmod.c | 2 ++ + arch/arm/plat-omap/omap_device.c | 6 ++++-- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c +index 87cc6d0..f3c0947 100644 +--- a/arch/arm/mach-omap2/omap_hwmod.c ++++ b/arch/arm/mach-omap2/omap_hwmod.c +@@ -138,6 +138,7 @@ + #include <linux/spinlock.h> + #include <linux/slab.h> + #include <linux/bootmem.h> ++#include <linux/export.h> + + #include <plat/clock.h> + #include <plat/omap_hwmod.h> +@@ -3076,6 +3077,7 @@ struct omap_hwmod *omap_hwmod_lookup(const char *name) + + return oh; + } ++EXPORT_SYMBOL(omap_hwmod_lookup); + + /** + * omap_hwmod_for_each - call function for each registered omap_hwmod +diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c +index 7a7d1f2..a15b715 100644 +--- a/arch/arm/plat-omap/omap_device.c ++++ b/arch/arm/plat-omap/omap_device.c +@@ -663,7 +663,7 @@ void omap_device_delete(struct omap_device *od) + * information. Returns ERR_PTR(-EINVAL) if @oh is NULL; otherwise, + * passes along the return value of omap_device_build_ss(). + */ +-struct platform_device __init *omap_device_build(const char *pdev_name, int pdev_id, ++struct platform_device *omap_device_build(const char *pdev_name, int pdev_id, + struct omap_hwmod *oh, void *pdata, + int pdata_len, + struct omap_device_pm_latency *pm_lats, +@@ -678,6 +678,7 @@ struct platform_device __init *omap_device_build(const char *pdev_name, int pdev + pdata_len, pm_lats, pm_lats_cnt, + is_early_device); + } ++EXPORT_SYMBOL(omap_device_build); + + /** + * omap_device_build_ss - build and register an omap_device with multiple hwmods +@@ -696,7 +697,7 @@ struct platform_device __init *omap_device_build(const char *pdev_name, int pdev + * platform_device record. Returns an ERR_PTR() on error, or passes + * along the return value of omap_device_register(). + */ +-struct platform_device __init *omap_device_build_ss(const char *pdev_name, int pdev_id, ++struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id, + struct omap_hwmod **ohs, int oh_cnt, + void *pdata, int pdata_len, + struct omap_device_pm_latency *pm_lats, +@@ -751,6 +752,7 @@ odbs_exit: + + return ERR_PTR(ret); + } ++EXPORT_SYMBOL(omap_device_build_ss); + + /** + * omap_early_device_register - register an omap_device as an early platform diff --git a/patches/linux-3.7-rc6/0121-gpio-keys-Pinctrl-fy.patch b/patches/linux-3.7-rc6/0121-gpio-keys-Pinctrl-fy.patch new file mode 100644 index 0000000..3cf53f7 --- /dev/null +++ b/patches/linux-3.7-rc6/0121-gpio-keys-Pinctrl-fy.patch @@ -0,0 +1,40 @@ +From ae6cef3b75d1ab9a32fdd95d7a9ed516aa587972 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Wed, 17 Oct 2012 20:17:36 +0300 +Subject: [PATCH] gpio-keys: Pinctrl-fy + +--- + drivers/input/keyboard/gpio_keys.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c +index 6a68041..e421082 100644 +--- a/drivers/input/keyboard/gpio_keys.c ++++ b/drivers/input/keyboard/gpio_keys.c +@@ -29,6 +29,7 @@ + #include <linux/of_platform.h> + #include <linux/of_gpio.h> + #include <linux/spinlock.h> ++#include <linux/pinctrl/consumer.h> + + struct gpio_button_data { + const struct gpio_keys_button *button; +@@ -666,6 +667,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) + struct input_dev *input; + int i, error; + int wakeup = 0; ++ struct pinctrl *pinctrl; + + if (!pdata) { + pdata = gpio_keys_get_devtree_pdata(dev); +@@ -731,6 +733,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) + goto fail3; + } + ++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev); ++ if (IS_ERR(pinctrl)) ++ dev_warn(&pdev->dev, "unable to select pin group\n"); ++ + /* get current state of buttons that are connected to GPIOs */ + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; diff --git a/patches/linux-3.7-rc6/0122-tps65217-Allow-placement-elsewhere-than-parent-mfd-d.patch b/patches/linux-3.7-rc6/0122-tps65217-Allow-placement-elsewhere-than-parent-mfd-d.patch new file mode 100644 index 0000000..bdf9716 --- /dev/null +++ b/patches/linux-3.7-rc6/0122-tps65217-Allow-placement-elsewhere-than-parent-mfd-d.patch @@ -0,0 +1,195 @@ +From 60b3cfc365647a38b67719be3a134c392f1f6fe6 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Wed, 17 Oct 2012 20:17:57 +0300 +Subject: [PATCH] tps65217: Allow placement elsewhere than parent mfd device. + +The current code expect the configuration of the backlight to stay +constant after initialization. This patch allows to move it around. +--- + drivers/video/backlight/tps65217_bl.c | 103 +++++++++++++++++++++++++++++---- + 1 file changed, 92 insertions(+), 11 deletions(-) + +diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c +index 7088163..69c1dfe 100644 +--- a/drivers/video/backlight/tps65217_bl.c ++++ b/drivers/video/backlight/tps65217_bl.c +@@ -24,8 +24,11 @@ + #include <linux/module.h> + #include <linux/platform_device.h> + #include <linux/slab.h> ++#include <linux/i2c.h> ++#include <linux/of_i2c.h> + + struct tps65217_bl { ++ struct i2c_client *i2c_client; + struct tps65217 *tps; + struct device *dev; + struct backlight_device *bl; +@@ -98,8 +101,6 @@ static int tps65217_bl_update_status(struct backlight_device *bl) + return rc; + } + +- dev_dbg(tps65217_bl->dev, "brightness set to %d\n", brightness); +- + if (!tps65217_bl->is_enabled) + rc = tps65217_bl_enable(tps65217_bl); + } else { +@@ -187,14 +188,69 @@ static int tps65217_bl_hw_init(struct tps65217_bl *tps65217_bl, + + #ifdef CONFIG_OF + static struct tps65217_bl_pdata * +-tps65217_bl_parse_dt(struct platform_device *pdev) ++tps65217_bl_parse_dt(struct platform_device *pdev, struct tps65217 **tpsp, ++ int *brightnessp) + { +- struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); +- struct device_node *node = of_node_get(tps->dev->of_node); ++ struct i2c_client *i2c_client; ++ struct tps65217 *tps; ++ struct device_node *node, *rnode, *pnode; + struct tps65217_bl_pdata *pdata, *err; ++ u32 tps_handle; + u32 val; + +- node = of_find_node_by_name(node, "backlight"); ++ tps = NULL; ++ node = NULL; ++ *brightnessp = 0; ++ ++ /* our node (compatible) */ ++ pnode = pdev->dev.of_node; ++ if (pnode != NULL && ++ of_property_read_u32(pnode, "tps", &tps_handle) == 0) { ++ /* we are not instantiated from the mfd */ ++ node = of_find_node_by_phandle(tps_handle); ++ if (node == NULL) { ++ dev_err(&pdev->dev, "failed to find the tps node\n"); ++ err = ERR_PTR(-EINVAL); ++ goto err; ++ } ++ i2c_client = of_find_i2c_device_by_node(node); ++ if (i2c_client == NULL) { ++ dev_err(&pdev->dev, "failed to find the i2c device " ++ "of tps node\n"); ++ err = ERR_PTR(-EINVAL); ++ goto err; ++ } ++ /* yeah this is gross; the whole concept is */ ++ tps = i2c_get_clientdata(i2c_client); ++ if (tps == NULL) { ++ dev_err(&pdev->dev, "failed to get tps structure\n"); ++ err = ERR_PTR(-EINVAL); ++ goto err; ++ } ++ ++ /* read default brightness */ ++ val = 0; ++ of_property_read_u32(pnode, "brightness", &val); ++ if (val >= 100) ++ val = 100; ++ ++ *brightnessp = val; ++ ++ /* no need for this anymore */ ++ of_node_put(node); ++ ++ dev_info(&pdev->dev, "got tps=%p from handle 0x%x\n", tps, tps_handle); ++ } ++ ++ if (tps == NULL) ++ tps = dev_get_drvdata(pdev->dev.parent); ++ ++ rnode = of_node_get(tps->dev->of_node); ++ ++ node = of_find_node_by_name(rnode, "backlight"); ++ of_node_put(rnode); ++ rnode = NULL; ++ + if (!node) + return ERR_PTR(-ENODEV); + +@@ -247,6 +303,7 @@ tps65217_bl_parse_dt(struct platform_device *pdev) + + of_node_put(node); + ++ *tpsp = tps; + return pdata; + + err: +@@ -254,9 +311,16 @@ err: + + return err; + } ++ ++static struct of_device_id tps65217_backlight_of_match[] = { ++ { .compatible = "tps65217-backlight" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, tps65217_backlight_of_match); + #else + static struct tps65217_bl_pdata * +-tps65217_bl_parse_dt(struct platform_device *pdev) ++tps65217_bl_parse_dt(struct platform_device *pdev, struct tps65217 **tpsp, ++ int *brightnessp) + { + return NULL; + } +@@ -265,13 +329,16 @@ tps65217_bl_parse_dt(struct platform_device *pdev) + static int tps65217_bl_probe(struct platform_device *pdev) + { + int rc; +- struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); ++ struct tps65217 *tps; + struct tps65217_bl *tps65217_bl; + struct tps65217_bl_pdata *pdata; + struct backlight_properties bl_props; ++ int brightness = 0; + +- if (tps->dev->of_node) { +- pdata = tps65217_bl_parse_dt(pdev); ++ tps = NULL; ++ ++ if (pdev->dev.of_node) { ++ pdata = tps65217_bl_parse_dt(pdev, &tps, &brightness); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } else { +@@ -281,6 +348,14 @@ static int tps65217_bl_probe(struct platform_device *pdev) + } + + pdata = pdev->dev.platform_data; ++ ++ /* get the parent device */ ++ tps = dev_get_drvdata(pdev->dev.parent); ++ } ++ ++ if (tps == NULL) { ++ dev_err(&pdev->dev, "failed to find tps\n"); ++ return -EINVAL; + } + + tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl), +@@ -311,9 +386,14 @@ static int tps65217_bl_probe(struct platform_device *pdev) + return PTR_ERR(tps65217_bl->bl); + } + +- tps65217_bl->bl->props.brightness = 0; ++ tps65217_bl->bl->props.brightness = brightness; + platform_set_drvdata(pdev, tps65217_bl); + ++ /* update with initial settings */ ++ tps65217_bl_update_status(tps65217_bl->bl); ++ ++ dev_info(&pdev->dev, "OK.\n"); ++ + return 0; + } + +@@ -332,6 +412,7 @@ static struct platform_driver tps65217_bl_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "tps65217-bl", ++ .of_match_table = of_match_ptr(tps65217_backlight_of_match), + }, + }; + diff --git a/patches/linux-3.7-rc6/0123-pwm-export-of_pwm_request.patch b/patches/linux-3.7-rc6/0123-pwm-export-of_pwm_request.patch new file mode 100644 index 0000000..2223575 --- /dev/null +++ b/patches/linux-3.7-rc6/0123-pwm-export-of_pwm_request.patch @@ -0,0 +1,67 @@ +From fbcf0d6f0fb39e6d70d41f32844a9c13622010ea Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Fri, 19 Oct 2012 10:38:00 +0300 +Subject: [PATCH] pwm: export of_pwm_request + +No need to hide this, it's useful. +--- + drivers/pwm/core.c | 6 +++++- + include/linux/pwm.h | 7 +++++++ + 2 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c +index f5acdaa..f8c7e6b 100644 +--- a/drivers/pwm/core.c ++++ b/drivers/pwm/core.c +@@ -457,7 +457,7 @@ static struct pwm_chip *of_node_to_pwmchip(struct device_node *np) + * becomes mandatory for devices that look up the PWM device via the con_id + * parameter. + */ +-static struct pwm_device *of_pwm_request(struct device_node *np, ++struct pwm_device *of_pwm_request(struct device_node *np, + const char *con_id) + { + struct pwm_device *pwm = NULL; +@@ -466,6 +466,9 @@ static struct pwm_device *of_pwm_request(struct device_node *np, + int index = 0; + int err; + ++ if (!np) ++ return ERR_PTR(-ENODEV); ++ + if (con_id) { + index = of_property_match_string(np, "pwm-names", con_id); + if (index < 0) +@@ -516,6 +519,7 @@ put: + + return pwm; + } ++EXPORT_SYMBOL(of_pwm_request); + + /** + * pwm_add_table() - register PWM device consumers +diff --git a/include/linux/pwm.h b/include/linux/pwm.h +index 112b314..fafbb1c 100644 +--- a/include/linux/pwm.h ++++ b/include/linux/pwm.h +@@ -171,6 +171,7 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, + unsigned int index, + const char *label); + ++struct pwm_device *of_pwm_request(struct device_node *np, const char *consumer); + struct pwm_device *pwm_get(struct device *dev, const char *consumer); + void pwm_put(struct pwm_device *pwm); + +@@ -204,6 +205,12 @@ static inline struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, + return ERR_PTR(-ENODEV); + } + ++static inline struct pwm_device *of_pwm_request(struct device_node *np, ++ const char *consumer) ++{ ++ return ERR_PTR(-ENODEV); ++} ++ + static inline struct pwm_device *pwm_get(struct device *dev, + const char *consumer) + { diff --git a/patches/linux-3.7-rc6/0124-i2c-Export-capability-to-probe-devices.patch b/patches/linux-3.7-rc6/0124-i2c-Export-capability-to-probe-devices.patch new file mode 100644 index 0000000..d72b464 --- /dev/null +++ b/patches/linux-3.7-rc6/0124-i2c-Export-capability-to-probe-devices.patch @@ -0,0 +1,65 @@ +From b431efb8fef34dc5ea688fcf98851f4a2d42ef72 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Sat, 20 Oct 2012 14:08:17 +0300 +Subject: [PATCH] i2c: Export capability to probe devices + +Probe devices for a node other that the adapter node. +--- + drivers/of/of_i2c.c | 14 ++++++++++---- + include/linux/of_i2c.h | 3 +++ + 2 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c +index 3550f3b..7f36b05 100644 +--- a/drivers/of/of_i2c.c ++++ b/drivers/of/of_i2c.c +@@ -18,18 +18,18 @@ + #include <linux/of_irq.h> + #include <linux/module.h> + +-void of_i2c_register_devices(struct i2c_adapter *adap) ++void of_i2c_register_node_devices(struct i2c_adapter *adap, ++ struct device_node *parent_node) + { + void *result; + struct device_node *node; + +- /* Only register child devices if the adapter has a node pointer set */ +- if (!adap->dev.of_node) ++ if (!parent_node) + return; + + dev_dbg(&adap->dev, "of_i2c: walking child nodes\n"); + +- for_each_child_of_node(adap->dev.of_node, node) { ++ for_each_child_of_node(parent_node, node) { + struct i2c_board_info info = {}; + struct dev_archdata dev_ad = {}; + const __be32 *addr; +@@ -76,6 +76,12 @@ void of_i2c_register_devices(struct i2c_adapter *adap) + } + } + } ++EXPORT_SYMBOL(of_i2c_register_node_devices); ++ ++void of_i2c_register_devices(struct i2c_adapter *adap) ++{ ++ of_i2c_register_node_devices(adap, adap->dev.of_node); ++} + EXPORT_SYMBOL(of_i2c_register_devices); + + static int of_dev_node_match(struct device *dev, void *data) +diff --git a/include/linux/of_i2c.h b/include/linux/of_i2c.h +index 1cb775f..d2f8ebb6 100644 +--- a/include/linux/of_i2c.h ++++ b/include/linux/of_i2c.h +@@ -15,6 +15,9 @@ + #if defined(CONFIG_OF_I2C) || defined(CONFIG_OF_I2C_MODULE) + #include <linux/i2c.h> + ++extern void of_i2c_register_node_devices(struct i2c_adapter *adap, ++ struct device_node *parent_node); ++ + extern void of_i2c_register_devices(struct i2c_adapter *adap); + + /* must call put_device() when done with returned i2c_client device */ diff --git a/patches/linux-3.7-rc6/0125-pwm-backlight-Pinctrl-fy.patch b/patches/linux-3.7-rc6/0125-pwm-backlight-Pinctrl-fy.patch new file mode 100644 index 0000000..ccf1ddc --- /dev/null +++ b/patches/linux-3.7-rc6/0125-pwm-backlight-Pinctrl-fy.patch @@ -0,0 +1,37 @@ +From cd1f5ff870b0977e4d6a4454c2758806f5f524c2 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Tue, 23 Oct 2012 11:48:58 +0300 +Subject: [PATCH] pwm-backlight: Pinctrl-fy + +--- + drivers/video/backlight/pwm_bl.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c +index 0c91023..f3b6194 100644 +--- a/drivers/video/backlight/pwm_bl.c ++++ b/drivers/video/backlight/pwm_bl.c +@@ -20,6 +20,8 @@ + #include <linux/pwm.h> + #include <linux/pwm_backlight.h> + #include <linux/slab.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/err.h> + + struct pwm_bl_data { + struct pwm_device *pwm; +@@ -180,9 +182,14 @@ static int pwm_backlight_probe(struct platform_device *pdev) + struct backlight_properties props; + struct backlight_device *bl; + struct pwm_bl_data *pb; ++ struct pinctrl *pinctrl; + unsigned int max; + int ret; + ++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev); ++ if (IS_ERR(pinctrl)) ++ dev_warn(&pdev->dev, "unable to select pin group\n"); ++ + if (!data) { + ret = pwm_backlight_parse_dt(&pdev->dev, &defdata); + if (ret < 0) { diff --git a/patches/linux-3.7-rc6/0126-spi-Export-OF-interfaces-for-capebus-use.patch b/patches/linux-3.7-rc6/0126-spi-Export-OF-interfaces-for-capebus-use.patch new file mode 100644 index 0000000..deac5fc --- /dev/null +++ b/patches/linux-3.7-rc6/0126-spi-Export-OF-interfaces-for-capebus-use.patch @@ -0,0 +1,119 @@ +From 0f227d7527b91f7c3536842549fc8de50c16b956 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Tue, 23 Oct 2012 13:23:14 +0300 +Subject: [PATCH] spi: Export OF interfaces for capebus use. + +--- + drivers/spi/spi.c | 31 +++++++++++++++++++++++-------- + include/linux/spi/spi.h | 18 ++++++++++++++++++ + 2 files changed, 41 insertions(+), 8 deletions(-) + +diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c +index 84c2861..f8de2f2 100644 +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -801,14 +801,17 @@ err_init_queue: + /*-------------------------------------------------------------------------*/ + + #if defined(CONFIG_OF) && !defined(CONFIG_SPARC) ++ + /** +- * of_register_spi_devices() - Register child devices onto the SPI bus ++ * of_register_node_spi_devices() - Register child devices onto the SPI bus + * @master: Pointer to spi_master device ++ * @parent_node: Pointer to the device node containg the devices + * + * Registers an spi_device for each child node of master node which has a 'reg' + * property. + */ +-static void of_register_spi_devices(struct spi_master *master) ++void of_register_node_spi_devices(struct spi_master *master, ++ struct device_node *parent_node) + { + struct spi_device *spi; + struct device_node *nc; +@@ -816,10 +819,10 @@ static void of_register_spi_devices(struct spi_master *master) + int rc; + int len; + +- if (!master->dev.of_node) ++ if (!parent_node) + return; + +- for_each_child_of_node(master->dev.of_node, nc) { ++ for_each_child_of_node(parent_node, nc) { + /* Alloc an spi_device */ + spi = spi_alloc_device(master); + if (!spi) { +@@ -884,8 +887,20 @@ static void of_register_spi_devices(struct spi_master *master) + + } + } +-#else +-static void of_register_spi_devices(struct spi_master *master) { } ++EXPORT_SYMBOL_GPL(of_register_node_spi_devices); ++ ++/** ++ * of_register_spi_devices() - Register child devices onto the SPI bus ++ * @master: Pointer to spi_master device ++ * ++ * Registers an spi_device for each child node of master node which has a 'reg' ++ * property. ++ */ ++void of_register_spi_devices(struct spi_master *master) ++{ ++ of_register_node_spi_devices(master, master->dev.of_node); ++} ++EXPORT_SYMBOL_GPL(of_register_spi_devices); + #endif + + static void spi_master_release(struct device *dev) +@@ -896,12 +911,12 @@ static void spi_master_release(struct device *dev) + kfree(master); + } + +-static struct class spi_master_class = { ++struct class spi_master_class = { + .name = "spi_master", + .owner = THIS_MODULE, + .dev_release = spi_master_release, + }; +- ++EXPORT_SYMBOL_GPL(spi_master_class); + + + /** +diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h +index fa702ae..618aa5e 100644 +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -30,6 +30,8 @@ + */ + extern struct bus_type spi_bus_type; + ++extern struct class spi_master_class; ++ + /** + * struct spi_device - Master side proxy for an SPI slave device + * @dev: Driver model representation of the device. +@@ -856,4 +858,20 @@ spi_unregister_device(struct spi_device *spi) + extern const struct spi_device_id * + spi_get_device_id(const struct spi_device *sdev); + ++#if defined(CONFIG_OF) && !defined(CONFIG_SPARC) ++ ++void of_register_node_spi_devices(struct spi_master *master, ++ struct device_node *parent_node); ++ ++void of_register_spi_devices(struct spi_master *master); ++ ++#else ++ ++static inline void of_register_node_spi_devices(struct spi_master *master, ++ struct device_node *parent_node) { } ++ ++static inline void of_register_spi_devices(struct spi_master *master) { } ++ ++#endif ++ + #endif /* __LINUX_SPI_H */ diff --git a/patches/linux-3.7-rc6/0127-w1-gpio-Pinctrl-fy.patch b/patches/linux-3.7-rc6/0127-w1-gpio-Pinctrl-fy.patch new file mode 100644 index 0000000..c735d63 --- /dev/null +++ b/patches/linux-3.7-rc6/0127-w1-gpio-Pinctrl-fy.patch @@ -0,0 +1,36 @@ +From 24e009b4e579b589dd3a3bed2577e22517b21054 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Wed, 24 Oct 2012 09:54:37 +0300 +Subject: [PATCH] w1-gpio: Pinctrl-fy + +--- + drivers/w1/masters/w1-gpio.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c +index 6012c4e..aec35bd 100644 +--- a/drivers/w1/masters/w1-gpio.c ++++ b/drivers/w1/masters/w1-gpio.c +@@ -16,6 +16,8 @@ + #include <linux/gpio.h> + #include <linux/of_platform.h> + #include <linux/of_gpio.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/err.h> + + #include "../w1.h" + #include "../w1_int.h" +@@ -85,8 +87,13 @@ static int __init w1_gpio_probe(struct platform_device *pdev) + { + struct w1_bus_master *master; + struct w1_gpio_platform_data *pdata; ++ struct pinctrl *pinctrl; + int err; + ++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev); ++ if (IS_ERR(pinctrl)) ++ dev_warn(&pdev->dev, "unable to select pin group\n"); ++ + err = w1_gpio_probe_dt(pdev); + if (err < 0) + return err; diff --git a/patches/linux-3.7-rc6/0128-w1-gpio-Simplify-get-rid-of-defines.patch b/patches/linux-3.7-rc6/0128-w1-gpio-Simplify-get-rid-of-defines.patch new file mode 100644 index 0000000..dd5640f --- /dev/null +++ b/patches/linux-3.7-rc6/0128-w1-gpio-Simplify-get-rid-of-defines.patch @@ -0,0 +1,141 @@ +From 90429eda58f60e4684b5aba4ad8a6ff72da8f94e Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Wed, 24 Oct 2012 16:49:53 +0300 +Subject: [PATCH] w1-gpio: Simplify & get rid of defines + +--- + drivers/w1/masters/w1-gpio.c | 58 +++++++++++++++++++----------------------- + 1 file changed, 26 insertions(+), 32 deletions(-) + +diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c +index aec35bd..85b363a 100644 +--- a/drivers/w1/masters/w1-gpio.c ++++ b/drivers/w1/masters/w1-gpio.c +@@ -18,6 +18,7 @@ + #include <linux/of_gpio.h> + #include <linux/pinctrl/consumer.h> + #include <linux/err.h> ++#include <linux/of.h> + + #include "../w1.h" + #include "../w1_int.h" +@@ -46,7 +47,6 @@ static u8 w1_gpio_read_bit(void *data) + return gpio_get_value(pdata->pin) ? 1 : 0; + } + +-#ifdef CONFIG_OF + static struct of_device_id w1_gpio_dt_ids[] = { + { .compatible = "w1-gpio" }, + {} +@@ -57,11 +57,6 @@ static int w1_gpio_probe_dt(struct platform_device *pdev) + { + struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; + struct device_node *np = pdev->dev.of_node; +- const struct of_device_id *of_id = +- of_match_device(w1_gpio_dt_ids, &pdev->dev); +- +- if (!of_id) +- return 0; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) +@@ -76,12 +71,6 @@ static int w1_gpio_probe_dt(struct platform_device *pdev) + + return 0; + } +-#else +-static int w1_gpio_probe_dt(struct platform_device *pdev) +-{ +- return 0; +-} +-#endif + + static int __init w1_gpio_probe(struct platform_device *pdev) + { +@@ -94,28 +83,41 @@ static int __init w1_gpio_probe(struct platform_device *pdev) + if (IS_ERR(pinctrl)) + dev_warn(&pdev->dev, "unable to select pin group\n"); + +- err = w1_gpio_probe_dt(pdev); +- if (err < 0) +- return err; ++ if (of_have_populated_dt()) { ++ err = w1_gpio_probe_dt(pdev); ++ if (err < 0) { ++ dev_err(&pdev->dev, "Failed to parse DT\n"); ++ return err; ++ } ++ } + + pdata = pdev->dev.platform_data; + +- if (!pdata) ++ if (!pdata) { ++ dev_err(&pdev->dev, "No configuration data\n"); + return -ENXIO; ++ } + + master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL); +- if (!master) ++ if (!master) { ++ dev_err(&pdev->dev, "Out of memory\n"); + return -ENOMEM; ++ } + + err = gpio_request(pdata->pin, "w1"); +- if (err) ++ if (err) { ++ dev_err(&pdev->dev, "gpio_request (pin) failed\n"); + goto free_master; ++ } + + if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { + err = gpio_request_one(pdata->ext_pullup_enable_pin, + GPIOF_INIT_LOW, "w1 pullup"); +- if (err < 0) ++ if (err < 0) { ++ dev_err(&pdev->dev, "gpio_request_one " ++ "(ext_pullup_enable_pin) failed\n"); + goto free_gpio; ++ } + } + + master->data = pdata; +@@ -130,8 +132,10 @@ static int __init w1_gpio_probe(struct platform_device *pdev) + } + + err = w1_add_master_device(master); +- if (err) ++ if (err) { ++ dev_err(&pdev->dev, "w1_add_master device failed\n"); + goto free_gpio_ext_pu; ++ } + + if (pdata->enable_external_pullup) + pdata->enable_external_pullup(1); +@@ -205,23 +209,13 @@ static struct platform_driver w1_gpio_driver = { + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(w1_gpio_dt_ids), + }, ++ .probe = w1_gpio_probe, + .remove = __exit_p(w1_gpio_remove), + .suspend = w1_gpio_suspend, + .resume = w1_gpio_resume, + }; + +-static int __init w1_gpio_init(void) +-{ +- return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe); +-} +- +-static void __exit w1_gpio_exit(void) +-{ +- platform_driver_unregister(&w1_gpio_driver); +-} +- +-module_init(w1_gpio_init); +-module_exit(w1_gpio_exit); ++module_platform_driver(w1_gpio_driver); + + MODULE_DESCRIPTION("GPIO w1 bus master driver"); + MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>"); diff --git a/patches/linux-3.7-rc6/0129-arm-dt-Enable-DT-proc-updates.patch b/patches/linux-3.7-rc6/0129-arm-dt-Enable-DT-proc-updates.patch new file mode 100644 index 0000000..0442646 --- /dev/null +++ b/patches/linux-3.7-rc6/0129-arm-dt-Enable-DT-proc-updates.patch @@ -0,0 +1,22 @@ +From 291e077b7d6d86c75b1ecbd894072d6256140a7e Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Fri, 26 Oct 2012 16:11:46 +0300 +Subject: [PATCH] arm-dt: Enable DT proc updates. + +--- + arch/arm/include/asm/prom.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm/include/asm/prom.h b/arch/arm/include/asm/prom.h +index aeae9c6..6d65ba2 100644 +--- a/arch/arm/include/asm/prom.h ++++ b/arch/arm/include/asm/prom.h +@@ -11,6 +11,8 @@ + #ifndef __ASMARM_PROM_H + #define __ASMARM_PROM_H + ++#define HAVE_ARCH_DEVTREE_FIXUPS ++ + #ifdef CONFIG_OF + + extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys); diff --git a/patches/linux-3.7-rc6/0130-ARM-CUSTOM-Build-a-uImage-with-dtb-already-appended.patch b/patches/linux-3.7-rc6/0130-ARM-CUSTOM-Build-a-uImage-with-dtb-already-appended.patch new file mode 100644 index 0000000..f5470f4 --- /dev/null +++ b/patches/linux-3.7-rc6/0130-ARM-CUSTOM-Build-a-uImage-with-dtb-already-appended.patch @@ -0,0 +1,57 @@ +From 99b06dce3bcdf014160203950451b9f84269c3e2 Mon Sep 17 00:00:00 2001 +From: Grant Likely <grant.likely@secretlab.ca> +Date: Tue, 2 Aug 2011 15:30:09 +0100 +Subject: [PATCH] ARM: CUSTOM: Build a uImage with dtb already appended + +Do not commit to mainline; this is a useful hack only for now. + +Signed-off-by: Grant Likely <grant.likely@secretlab.ca> +Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com> + +Conflicts: + + arch/arm/Makefile +--- + arch/arm/Makefile | 3 +++ + arch/arm/boot/Makefile | 7 +++++++ + 2 files changed, 10 insertions(+) + +diff --git a/arch/arm/Makefile b/arch/arm/Makefile +index 5f914fc..05df486 100644 +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -291,6 +291,9 @@ zImage Image xipImage bootpImage uImage: vmlinux + zinstall uinstall install: vmlinux + $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ + ++uImage-dtb.%: ++ $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ ++ + %.dtb: scripts + $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ + +diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile +index 9137df5..416fbe9 100644 +--- a/arch/arm/boot/Makefile ++++ b/arch/arm/boot/Makefile +@@ -57,6 +57,9 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE + $(call if_changed,objcopy) + @$(kecho) ' Kernel: $@ is ready' + ++$(obj)/zImage-dtb.%: $(obj)/%.dtb $(obj)/zImage ++ cat $(obj)/zImage $< > $@ ++ + endif + + targets += $(dtb-y) +@@ -92,6 +95,10 @@ $(obj)/uImage: $(obj)/zImage FORCE + $(call if_changed,uimage) + @$(kecho) ' Image $@ is ready' + ++$(obj)/uImage-dtb.%: $(obj)/zImage-dtb.% FORCE ++ $(call if_changed,uimage) ++ @echo ' Image $@ is ready' ++ + $(obj)/bootp/bootp: $(obj)/zImage initrd FORCE + $(Q)$(MAKE) $(build)=$(obj)/bootp $@ + @: diff --git a/patches/linux-3.7-rc6/0131-beaglebone-create-a-shared-dtsi-for-beaglebone-based.patch b/patches/linux-3.7-rc6/0131-beaglebone-create-a-shared-dtsi-for-beaglebone-based.patch new file mode 100644 index 0000000..7d33a69 --- /dev/null +++ b/patches/linux-3.7-rc6/0131-beaglebone-create-a-shared-dtsi-for-beaglebone-based.patch @@ -0,0 +1,501 @@ +From 69ae0a2048568b5ebc61c947153b4935b644f4b3 Mon Sep 17 00:00:00 2001 +From: Koen Kooi <koen@dominion.thruhere.net> +Date: Tue, 30 Oct 2012 12:30:18 +0100 +Subject: [PATCH] beaglebone: create a shared dtsi for beaglebone based boards + and add a new dts for bonelt + +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/boot/dts/Makefile | 3 +- + arch/arm/boot/dts/am335x-bone-common.dtsi | 201 +++++++++++++++++++++++++ + arch/arm/boot/dts/am335x-bone.dts | 233 +---------------------------- + arch/arm/boot/dts/am335x-bonelt.dts | 17 +++ + 4 files changed, 221 insertions(+), 233 deletions(-) + create mode 100644 arch/arm/boot/dts/am335x-bone-common.dtsi + create mode 100644 arch/arm/boot/dts/am335x-bonelt.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index f37cf9f..607114b 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -72,7 +72,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \ + omap4-sdp.dtb \ + omap5-evm.dtb \ + am335x-evm.dtb \ +- am335x-bone.dtb ++ am335x-bone.dtb \ ++ am335x-bonelt.dtb + dtb-$(CONFIG_ARCH_PRIMA2) += prima2-evb.dtb + dtb-$(CONFIG_ARCH_U8500) += snowball.dtb + dtb-$(CONFIG_ARCH_SHMOBILE) += emev2-kzm9d.dtb \ +diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi +new file mode 100644 +index 0000000..e674a19 +--- /dev/null ++++ b/arch/arm/boot/dts/am335x-bone-common.dtsi +@@ -0,0 +1,201 @@ ++/* ++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++/include/ "am33xx.dtsi" ++ ++/ { ++ model = "TI AM335x BeagleBone"; ++ compatible = "ti,am335x-bone", "ti,am33xx"; ++ ++ cpus { ++ cpu@0 { ++ cpu0-supply = <&dcdc2_reg>; ++ }; ++ }; ++ ++ memory { ++ device_type = "memory"; ++ reg = <0x80000000 0x10000000>; /* 256 MB */ ++ }; ++ ++ am3358_pinmux: pinmux@44e10800 { ++ spi1_pins: pinmux_spi1_pins { ++ pinctrl-single,pins = < ++ 0x190 0x13 /* mcasp0_aclkx.spi1_sclk, OUTPUT_PULLUP | MODE3 */ ++ 0x194 0x33 /* mcasp0_fsx.spi1_d0, INPUT_PULLUP | MODE3 */ ++ 0x198 0x13 /* mcasp0_axr0.spi1_d1, OUTPUT_PULLUP | MODE3 */ ++ 0x19c 0x13 /* mcasp0_ahclkr.spi1_cs0, OUTPUT_PULLUP | MODE3 */ ++ >; ++ }; ++ lcd_pins: pinmux_lcd_pins { ++ pinctrl-single,pins = < ++ 0x1a4 0x17 /* mcasp0_fsr.gpio3_19, OUTPUT_PULLUP | MODE7 */ ++ 0x1ac 0x17 /* mcasp0_ahclkx.gpio3_21, OUTPUT_PULLUP | MODE7 */ ++ >; ++ }; ++ gpevt_pins: pinmux_gpevt_pins { ++ pinctrl-single,pins = < ++ 0x090 0x37 /* gpmc_advn_ale.gpio2_2, INPUT_PULLUP | MODE7 */ ++ >; ++ }; ++ userled_pins: pinmux_userled_pins { ++ pinctrl-single,pins = < ++ 0x54 0x7 /* gpmc_a5.gpio1_21, OUTPUT | MODE7 */ ++ 0x58 0x17 /* gpmc_a6.gpio1_22, OUTPUT_PULLUP | MODE7 */ ++ 0x5c 0x7 /* gpmc_a7.gpio1_23, OUTPUT | MODE7 */ ++ 0x60 0x17 /* gpmc_a8.gpio1_24, OUTPUT_PULLUP | MODE7 */ ++ >; ++ }; ++ }; ++ ++ ocp { ++ uart1: serial@44e09000 { ++ status = "okay"; ++ }; ++ ++ gpio-leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&userled_pins>; ++ ++ led0 { ++ label = "beaglebone:green:usr0"; ++ gpios = <&gpio2 21 0>; ++ linux,default-trigger = "heartbeat"; ++ default-state = "off"; ++ }; ++ ++ led1 { ++ label = "beaglebone:green:usr1"; ++ gpios = <&gpio2 22 0>; ++ linux,default-trigger = "mmc0"; ++ default-state = "off"; ++ }; ++ ++ led2 { ++ label = "beaglebone:green:usr2"; ++ gpios = <&gpio2 23 0>; ++ linux,default-trigger = "cpu0"; ++ default-state = "off"; ++ }; ++ ++ led3 { ++ label = "beaglebone:green:usr3"; ++ gpios = <&gpio2 24 0>; ++ default-state = "off"; ++ }; ++ }; ++ ++ i2c1: i2c@44e0b000 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ ++ tps: tps@24 { ++ reg = <0x24>; ++ }; ++ ++ }; ++ ++ gpevt { ++ compatible = "gpevt"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&gpevt_pins>; ++ dmas = <&edma 12>; ++ dma-names = "gpioevt"; ++ gpio-evt = <&gpio3 2 0>; ++ }; ++ }; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&ehrpwm1 0 500000 0>; ++ pwm-names = "st7735fb"; ++ brightness-levels = <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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100>; ++ default-brightness-level = <50>; /* index to the array above */ ++ }; ++}; ++ ++/include/ "tps65217.dtsi" ++ ++&tps { ++ regulators { ++ dcdc1_reg: regulator@0 { ++ regulator-always-on; ++ }; ++ ++ dcdc2_reg: regulator@1 { ++ /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */ ++ regulator-name = "vdd_mpu"; ++ regulator-min-microvolt = <925000>; ++ regulator-max-microvolt = <1325000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ dcdc3_reg: regulator@2 { ++ /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */ ++ regulator-name = "vdd_core"; ++ regulator-min-microvolt = <925000>; ++ regulator-max-microvolt = <1150000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ ldo1_reg: regulator@3 { ++ regulator-always-on; ++ }; ++ ++ ldo2_reg: regulator@4 { ++ regulator-always-on; ++ }; ++ ++ ldo3_reg: regulator@5 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ ldo4_reg: regulator@6 { ++ regulator-always-on; ++ }; ++ }; ++}; ++ ++&mmc1 { ++ vmmc-supply = <&ldo3_reg>; ++}; ++ ++&spi1 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi1_pins>; ++ ++ lcd@0 { ++ compatible = "adafruit,tft-lcd-1.8-green", "sitronix,st7735"; ++ spi-max-frequency = <8000000>; ++ reg = <0>; ++ spi-cpol; ++ spi-cpha; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&lcd_pins>; ++ st7735-rst = <&gpio4 19 0>; ++ st7735-dc = <&gpio4 21 0>; ++ }; ++}; ++ ++&edma { ++ ti,edma-xbar-event-map = <32 12>; ++}; ++ ++&cpsw_emac0 { ++ phy_id = "4a101000.mdio:00"; ++}; ++ ++&cpsw_emac1 { ++ phy_id = "4a101000.mdio:01"; ++}; +diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts +index 667842d..7f0b0df 100644 +--- a/arch/arm/boot/dts/am335x-bone.dts ++++ b/arch/arm/boot/dts/am335x-bone.dts +@@ -8,235 +8,4 @@ + /dts-v1/; + + /include/ "am33xx.dtsi" +- +-/ { +- model = "TI AM335x BeagleBone"; +- compatible = "ti,am335x-bone", "ti,am33xx"; +- +- cpus { +- cpu@0 { +- cpu0-supply = <&dcdc2_reg>; +- }; +- }; +- +- memory { +- device_type = "memory"; +- reg = <0x80000000 0x10000000>; /* 256 MB */ +- }; +- +- am3358_pinmux: pinmux@44e10800 { +- spi1_pins: pinmux_spi1_pins { +- pinctrl-single,pins = < +- 0x190 0x13 /* mcasp0_aclkx.spi1_sclk, OUTPUT_PULLUP | MODE3 */ +- 0x194 0x33 /* mcasp0_fsx.spi1_d0, INPUT_PULLUP | MODE3 */ +- 0x198 0x13 /* mcasp0_axr0.spi1_d1, OUTPUT_PULLUP | MODE3 */ +- 0x19c 0x13 /* mcasp0_ahclkr.spi1_cs0, OUTPUT_PULLUP | MODE3 */ +- >; +- }; +- lcd_pins: pinmux_lcd_pins { +- pinctrl-single,pins = < +- 0x1a4 0x17 /* mcasp0_fsr.gpio3_19, OUTPUT_PULLUP | MODE7 */ +- 0x1ac 0x17 /* mcasp0_ahclkx.gpio3_21, OUTPUT_PULLUP | MODE7 */ +- >; +- }; +- gpevt_pins: pinmux_gpevt_pins { +- pinctrl-single,pins = < +- 0x090 0x37 /* gpmc_advn_ale.gpio2_2, INPUT_PULLUP | MODE7 */ +- >; +- }; +- userled_pins: pinmux_userled_pins { +- pinctrl-single,pins = < +- 0x54 0x7 /* gpmc_a5.gpio1_21, OUTPUT | MODE7 */ +- 0x58 0x17 /* gpmc_a6.gpio1_22, OUTPUT_PULLUP | MODE7 */ +- 0x5c 0x7 /* gpmc_a7.gpio1_23, OUTPUT | MODE7 */ +- 0x60 0x17 /* gpmc_a8.gpio1_24, OUTPUT_PULLUP | MODE7 */ +- >; +- }; +- i2c2_pins: pinmux_i2c2_pins { +- pinctrl-single,pins = < +- 0x178 0x73 /* uart1_ctsn.i2c2_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */ +- 0x17c 0x73 /* uart1_rtsn.i2c2_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */ +- >; +- }; +- }; +- +- ocp { +- uart1: serial@44e09000 { +- status = "okay"; +- }; +- +- gpio-leds { +- compatible = "gpio-leds"; +- pinctrl-names = "default"; +- pinctrl-0 = <&userled_pins>; +- +- led0 { +- label = "beaglebone:green:usr0"; +- gpios = <&gpio2 21 0>; +- linux,default-trigger = "heartbeat"; +- default-state = "off"; +- }; +- +- led1 { +- label = "beaglebone:green:usr1"; +- gpios = <&gpio2 22 0>; +- linux,default-trigger = "mmc0"; +- default-state = "off"; +- }; +- +- led2 { +- label = "beaglebone:green:usr2"; +- gpios = <&gpio2 23 0>; +- linux,default-trigger = "cpu0"; +- default-state = "off"; +- }; +- +- led3 { +- label = "beaglebone:green:usr3"; +- gpios = <&gpio2 24 0>; +- default-state = "off"; +- }; +- }; +- +- gpevt { +- compatible = "gpevt"; +- pinctrl-names = "default"; +- pinctrl-0 = <&gpevt_pins>; +- dmas = <&edma 12>; +- dma-names = "gpioevt"; +- gpio-evt = <&gpio3 2 0>; +- }; +- }; +- +- backlight { +- compatible = "pwm-backlight"; +- pwms = <&ehrpwm1 0 500000 0>; +- pwm-names = "st7735fb"; +- brightness-levels = <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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100>; +- default-brightness-level = <50>; /* index to the array above */ +- }; +-}; +- +-&i2c0 { +- status = "okay"; +- clock-frequency = <400000>; +- +- tps: tps@24 { +- reg = <0x24>; +- }; +- +- baseboard_eeprom: baseboard_eeprom@50 { +- compatible = "at,24c256"; +- reg = <0x50>; +- }; +- +-}; +- +-&i2c2 { +- status = "okay"; +- pinctrl-names = "default"; +- pinctrl-0 = <&i2c2_pins>; +- +- clock-frequency = <100000>; +- +- /* OK, I know these are cape but for now it will do */ +- cape_eeprom_0: cape_eeprom_0@54 { +- compatible = "at,24c256"; +- reg = <0x54>; +- }; +- +- cape_eeprom_1: cape_eeprom_1@55 { +- compatible = "at,24c256"; +- reg = <0x55>; +- }; +- +- cape_eeprom_2: cape_eeprom_2@56 { +- compatible = "at,24c256"; +- reg = <0x56>; +- }; +- +- cape_eeprom_3: cape_eeprom_3@57 { +- compatible = "at,24c256"; +- reg = <0x57>; +- }; +-}; +- +-/include/ "tps65217.dtsi" +- +-&tps { +- regulators { +- dcdc1_reg: regulator@0 { +- regulator-always-on; +- }; +- +- dcdc2_reg: regulator@1 { +- /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */ +- regulator-name = "vdd_mpu"; +- regulator-min-microvolt = <925000>; +- regulator-max-microvolt = <1325000>; +- regulator-boot-on; +- regulator-always-on; +- }; +- +- dcdc3_reg: regulator@2 { +- /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */ +- regulator-name = "vdd_core"; +- regulator-min-microvolt = <925000>; +- regulator-max-microvolt = <1150000>; +- regulator-boot-on; +- regulator-always-on; +- }; +- +- ldo1_reg: regulator@3 { +- regulator-always-on; +- }; +- +- ldo2_reg: regulator@4 { +- regulator-always-on; +- }; +- +- ldo3_reg: regulator@5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- regulator-always-on; +- }; +- +- ldo4_reg: regulator@6 { +- regulator-always-on; +- }; +- }; +-}; +- +-&mmc1 { +- vmmc-supply = <&ldo3_reg>; +-}; +- +-&spi1 { +- status = "okay"; +- pinctrl-names = "default"; +- pinctrl-0 = <&spi1_pins>; +- +- lcd@0 { +- compatible = "adafruit,tft-lcd-1.8-green", "sitronix,st7735"; +- spi-max-frequency = <8000000>; +- reg = <0>; +- spi-cpol; +- spi-cpha; +- pinctrl-names = "default"; +- pinctrl-0 = <&lcd_pins>; +- st7735-rst = <&gpio4 19 0>; +- st7735-dc = <&gpio4 21 0>; +- }; +-}; +- +-&edma { +- ti,edma-xbar-event-map = <32 12>; +-}; +- +-&cpsw_emac0 { +- phy_id = "4a101000.mdio:00"; +-}; +- +-&cpsw_emac1 { +- phy_id = "4a101000.mdio:01"; +-}; ++/include/ "am335x-bone-common.dtsi" +diff --git a/arch/arm/boot/dts/am335x-bonelt.dts b/arch/arm/boot/dts/am335x-bonelt.dts +new file mode 100644 +index 0000000..03c875f +--- /dev/null ++++ b/arch/arm/boot/dts/am335x-bonelt.dts +@@ -0,0 +1,17 @@ ++/* ++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++/dts-v1/; ++ ++/include/ "am335x-bone-common.dtsi" ++ ++&mmc2 { ++ vmmc-supply = <&ldo3_reg>; ++ bus-width = <4>; ++ ti,non-removable; ++ status = "okay"; ++}; diff --git a/patches/linux-3.7-rc6/0132-beaglebone-enable-emmc-for-bonelt.patch b/patches/linux-3.7-rc6/0132-beaglebone-enable-emmc-for-bonelt.patch new file mode 100644 index 0000000..dfe59fe --- /dev/null +++ b/patches/linux-3.7-rc6/0132-beaglebone-enable-emmc-for-bonelt.patch @@ -0,0 +1,49 @@ +From 8b82f3581e17f14f6d7ac5bce043bb6bde7f9fe5 Mon Sep 17 00:00:00 2001 +From: Koen Kooi <koen@dominion.thruhere.net> +Date: Wed, 24 Oct 2012 11:47:13 +0200 +Subject: [PATCH] beaglebone: enable emmc for bonelt + +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/boot/dts/am335x-bone-common.dtsi | 1 + + arch/arm/boot/dts/am335x-bonelt.dts | 15 +++++++++++++++ + 2 files changed, 16 insertions(+) + +diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi +index e674a19..99240a5 100644 +--- a/arch/arm/boot/dts/am335x-bone-common.dtsi ++++ b/arch/arm/boot/dts/am335x-bone-common.dtsi +@@ -88,6 +88,7 @@ + label = "beaglebone:green:usr3"; + gpios = <&gpio2 24 0>; + default-state = "off"; ++ linux,default-trigger = "mmc1"; + }; + }; + +diff --git a/arch/arm/boot/dts/am335x-bonelt.dts b/arch/arm/boot/dts/am335x-bonelt.dts +index 03c875f..87257ac 100644 +--- a/arch/arm/boot/dts/am335x-bonelt.dts ++++ b/arch/arm/boot/dts/am335x-bonelt.dts +@@ -9,6 +9,21 @@ + + /include/ "am335x-bone-common.dtsi" + ++&userled_pins { ++ pinctrl-single,pins = < ++ 0x54 0x7 /* gpmc_a5.gpio1_21, OUTPUT | MODE7 */ ++ 0x58 0x17 /* gpmc_a6.gpio1_22, OUTPUT_PULLUP | MODE7 */ ++ 0x5c 0x7 /* gpmc_a7.gpio1_23, OUTPUT | MODE7 */ ++ 0x60 0x17 /* gpmc_a8.gpio1_24, OUTPUT_PULLUP | MODE7 */ ++ 0x00c 0x31 /* P8_6 gpmc_ad3.mmc1_dat1 PIN_INPUT_PULLUP | OMAP_MUX_MODE1 */ ++ 0x008 0x31 /* P8_5 gpmc_ad2.mmc1_dat2 PIN_INPUT_PULLUP | OMAP_MUX_MODE1 */ ++ 0x004 0x31 /* P8_24 gpmc_ad1.mmc1_dat1 PIN_INPUT_PULLUP | OMAP_MUX_MODE1 */ ++ 0x000 0x31 /* P8_25 gpmc_ad0.mmc1_dat0 PIN_INPUT_PULLUP | OMAP_MUX_MODE1 */ ++ 0x084 0x32 /* P8_20 gpmc_csn2.mmc1_cmd OMAP_MUX_MODE2 | AM33XX_PIN_INPUT_PULLUP} */ ++ 0x080 0x32 /* P8_21 gpmc_csn1.immc1_clk OMAP_MUX_MODE2 | AM33XX_PIN_INPUT_PULLUP} */ ++ >; ++}; ++ + &mmc2 { + vmmc-supply = <&ldo3_reg>; + bus-width = <4>; diff --git a/patches/linux-3.7-rc6/0133-capebus-Core-capebus-support.patch b/patches/linux-3.7-rc6/0133-capebus-Core-capebus-support.patch new file mode 100644 index 0000000..cf81437 --- /dev/null +++ b/patches/linux-3.7-rc6/0133-capebus-Core-capebus-support.patch @@ -0,0 +1,1383 @@ +From cad1e139fd88a35c63f0119541de52e5d9cb45fc Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Tue, 30 Oct 2012 21:06:06 +0200 +Subject: [PATCH] capebus: Core capebus support + +--- + drivers/Kconfig | 2 + + drivers/Makefile | 3 + + drivers/capebus/Kconfig | 17 ++ + drivers/capebus/Makefile | 8 + + drivers/capebus/capebus-driver.c | 608 ++++++++++++++++++++++++++++++++++++++ + drivers/capebus/capebus-probe.c | 320 ++++++++++++++++++++ + drivers/capebus/capebus-sysfs.c | 52 ++++ + include/linux/capebus.h | 298 +++++++++++++++++++ + 8 files changed, 1308 insertions(+) + create mode 100644 drivers/capebus/Kconfig + create mode 100644 drivers/capebus/Makefile + create mode 100644 drivers/capebus/capebus-driver.c + create mode 100644 drivers/capebus/capebus-probe.c + create mode 100644 drivers/capebus/capebus-sysfs.c + create mode 100644 include/linux/capebus.h + +diff --git a/drivers/Kconfig b/drivers/Kconfig +index dbdefa3..bfbe1d1 100644 +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -156,4 +156,6 @@ source "drivers/pwm/Kconfig" + + source "drivers/irqchip/Kconfig" + ++source "drivers/capebus/Kconfig" ++ + endmenu +diff --git a/drivers/Makefile b/drivers/Makefile +index a16a8d0..d7a103b 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -145,3 +145,6 @@ obj-$(CONFIG_EXTCON) += extcon/ + obj-$(CONFIG_MEMORY) += memory/ + obj-$(CONFIG_IIO) += iio/ + obj-$(CONFIG_VME_BUS) += vme/ ++ ++# Capebus ++obj-$(CONFIG_CAPEBUS) += capebus/ +diff --git a/drivers/capebus/Kconfig b/drivers/capebus/Kconfig +new file mode 100644 +index 0000000..cea1b68 +--- /dev/null ++++ b/drivers/capebus/Kconfig +@@ -0,0 +1,17 @@ ++# ++# Capebus core support ++# ++ ++menu "CAPEBUS support" ++ ++config CAPEBUS ++ bool "Capebus support" ++ default n ++ help ++ Enable to support capebus devices. ++ ++source "drivers/capebus/boards/Kconfig" ++ ++source "drivers/capebus/capes/Kconfig" ++ ++endmenu +diff --git a/drivers/capebus/Makefile b/drivers/capebus/Makefile +new file mode 100644 +index 0000000..45aa303 +--- /dev/null ++++ b/drivers/capebus/Makefile +@@ -0,0 +1,8 @@ ++# ++# Makefile for CAPEBUS devices ++# ++ ++obj-$(CONFIG_CAPEBUS) += capebus-probe.o \ ++ capebus-driver.o capebus-sysfs.o ++obj-$(CONFIG_CAPEBUS) += boards/ ++obj-$(CONFIG_CAPEBUS) += capes/ +diff --git a/drivers/capebus/capebus-driver.c b/drivers/capebus/capebus-driver.c +new file mode 100644 +index 0000000..82b1d1b +--- /dev/null ++++ b/drivers/capebus/capebus-driver.c +@@ -0,0 +1,608 @@ ++/* ++ * Capebus driver infrastructure ++ * ++ * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com> ++ * Copyright (C) 2012 Texas Instruments Inc. ++ * ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/device.h> ++#include <linux/mempolicy.h> ++#include <linux/string.h> ++#include <linux/slab.h> ++#include <linux/cpu.h> ++#include <linux/pm_runtime.h> ++#include <linux/suspend.h> ++ ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_platform.h> ++ ++#include <linux/capebus.h> ++ ++/** ++ * capebus_match_device - Tell if a cape device structure has a ++ * matching cape device id structure ++ * @drv: the cape driver to match against ++ * @dev: the cape device structure to match against ++ * ++ * Used by a driver to check whether a cape device present in the ++ * system is in its list of supported devices. Returns the matching ++ * cape_device_id structure or %NULL if there is no match. ++ */ ++static const struct cape_device_id *capebus_match_device( ++ struct cape_driver *drv, struct cape_dev *dev) ++{ ++ struct cape_bus *bus = dev->bus; ++ struct cape_slot *slot = dev->slot; ++ ++ BUG_ON(bus == NULL); ++ BUG_ON(slot == NULL); ++ BUG_ON(bus->ops == NULL); ++ BUG_ON(bus->ops->get_dev_id == NULL); ++ ++ return bus->ops->get_dev_id(slot); ++} ++ ++/** ++ * capebus_device_probe - check if a driver wants to claim a ++ * specific cape device ++ * @dev: cape device being probed ++ * ++ * returns 0 on success, else error. ++ * side-effect: cape_dev->driver is set to drv when drv claims cape_dev. ++ */ ++static int capebus_device_probe(struct device *dev) ++{ ++ const struct cape_device_id *id; ++ int error = 0; ++ struct cape_driver *drv; ++ struct cape_dev *cape_dev; ++ struct device *parent; ++ ++ drv = to_cape_driver(dev->driver); ++ cape_dev = to_cape_dev(dev); ++ cape_dev = capebus_dev_get(cape_dev); ++ ++ /* sanity checks */ ++ if (cape_dev == NULL || ++ cape_dev->bus == NULL || cape_dev->bus->ops == NULL || ++ cape_dev->driver != NULL || drv->probe == NULL) { ++ error = -EINVAL; ++ goto err_no_sanity; ++ } ++ ++ id = capebus_match_device(drv, cape_dev); ++ if (!id) { ++ error = -ENODEV; ++ goto err_no_match; ++ } ++ ++ /* The parent device must be in active state when probing */ ++ parent = cape_dev->dev.parent; ++ if (parent) ++ pm_runtime_get_sync(parent); ++ ++ /* Unbound cape devices are always set to disabled and suspended. ++ * During probe, the device is set to enabled and active and the ++ * usage count is incremented. If the driver supports runtime PM, ++ * it should call pm_runtime_put_noidle() in its probe routine and ++ * pm_runtime_get_noresume() in its remove routine. ++ */ ++ pm_runtime_get_noresume(&cape_dev->dev); ++ pm_runtime_set_active(&cape_dev->dev); ++ pm_runtime_enable(&cape_dev->dev); ++ ++ /* call the driver's probe method */ ++ error = drv->probe(cape_dev, id); ++ ++ /* release the parent no matter what */ ++ if (parent) ++ pm_runtime_put(parent); ++ ++ if (error != 0) ++ goto err_probe_fail; ++ ++ /* call the probed bus method */ ++ if (cape_dev->bus->ops->dev_probed != NULL) { ++ error = cape_dev->bus->ops->dev_probed(cape_dev); ++ if (error != 0) ++ goto err_dev_probed_fail; ++ } ++ ++ /* all is fine... */ ++ cape_dev->driver = drv; ++ cape_dev->added = 1; ++ ++ return 0; ++ ++err_dev_probed_fail: ++ if (drv->remove) { ++ pm_runtime_get_sync(&cape_dev->dev); ++ drv->remove(cape_dev); ++ pm_runtime_put_noidle(&cape_dev->dev); ++ } ++err_probe_fail: ++ pm_runtime_disable(&cape_dev->dev); ++ pm_runtime_set_suspended(&cape_dev->dev); ++ pm_runtime_put_noidle(&cape_dev->dev); ++err_no_match: ++ /* nothing */ ++err_no_sanity: ++ capebus_dev_put(cape_dev); ++ return error; ++} ++ ++static int capebus_device_remove(struct device *dev) ++{ ++ struct cape_dev *cape_dev = to_cape_dev(dev); ++ struct cape_driver *drv = cape_dev->driver; ++ ++ if (drv) { ++ /* call the removed bus method (if added prev.) */ ++ if (cape_dev->added) { ++ BUG_ON(cape_dev->bus == NULL); ++ BUG_ON(cape_dev->bus->ops == NULL); ++ if (cape_dev->bus->ops->dev_removed) ++ cape_dev->bus->ops->dev_removed(cape_dev); ++ cape_dev->added = 0; ++ } ++ if (drv->remove) { ++ pm_runtime_get_sync(dev); ++ drv->remove(cape_dev); ++ pm_runtime_put_noidle(dev); ++ } ++ cape_dev->driver = NULL; ++ } ++ ++ /* Undo the runtime PM settings in local_capebus_probe() */ ++ pm_runtime_disable(dev); ++ pm_runtime_set_suspended(dev); ++ pm_runtime_put_noidle(dev); ++ ++ capebus_dev_put(cape_dev); ++ return 0; ++} ++ ++static void capebus_device_shutdown(struct device *dev) ++{ ++ struct cape_dev *cape_dev = to_cape_dev(dev); ++ struct cape_driver *drv = cape_dev->driver; ++ ++ if (drv && drv->shutdown) ++ drv->shutdown(cape_dev); ++ ++ capebus_disable_device(cape_dev); ++ ++ if (!device_may_wakeup(dev)) ++ capebus_enable_wake(cape_dev, false); ++} ++ ++static int capebus_bus_match(struct device *dev, struct device_driver *drv); ++static int capebus_device_probe(struct device *dev); ++static int capebus_device_remove(struct device *dev); ++static void capebus_device_shutdown(struct device *dev); ++ ++struct bus_type capebus_bus_type = { ++ .name = "capebus", ++ .match = capebus_bus_match, ++ .probe = capebus_device_probe, ++ .remove = capebus_device_remove, ++ .shutdown = capebus_device_shutdown, ++ .dev_attrs = capebus_dev_attrs, ++ .bus_attrs = capebus_bus_attrs, ++ .pm = NULL, /* No PM for now */ ++}; ++EXPORT_SYMBOL(capebus_bus_type); ++ ++/** ++ * __capebus_register_driver - register a new capebus driver ++ * @drv: the driver structure to register ++ * @owner: owner module of drv ++ * @mod_name: module name string ++ * ++ * Adds the driver structure to the list of registered drivers. ++ * Returns a negative value on error, otherwise 0. ++ * If no error occurred, the driver remains registered even if ++ * no device was claimed during registration. ++ */ ++int __capebus_register_driver(struct cape_driver *drv, struct module *owner, ++ const char *mod_name) ++{ ++ /* initialize common driver fields */ ++ drv->driver.bus = &capebus_bus_type; ++ drv->driver.owner = owner; ++ drv->driver.mod_name = mod_name; ++ ++ /* register with core */ ++ return driver_register(&drv->driver); ++} ++EXPORT_SYMBOL(__capebus_register_driver); ++ ++/** ++ * capebus_unregister_driver - unregister a capebus driver ++ * @drv: the driver structure to unregister ++ * ++ * Deletes the driver structure from the list of registered cape drivers, ++ * gives it a chance to clean up by calling its remove() function for ++ * each device it was responsible for, and marks those devices as ++ * driverless. ++ */ ++ ++void ++capebus_unregister_driver(struct cape_driver *drv) ++{ ++ /* TODO: not really working properly */ ++ driver_unregister(&drv->driver); ++} ++EXPORT_SYMBOL(capebus_unregister_driver); ++ ++/** ++ * capebus_bus_match - Tell if a cape device structure has a matching ++ * cape device id structure ++ * @dev: the cape device structure to match against ++ * @drv: the device driver to search for matching cape device id structures ++ * ++ * Used by a driver to check whether a cape device present in the ++ * system is in its list of supported devices. Returns the matching ++ * cape_device_id structure or %NULL if there is no match. ++ */ ++static int capebus_bus_match(struct device *dev, struct device_driver *drv) ++{ ++ struct cape_dev *cape_dev = to_cape_dev(dev); ++ struct cape_driver *cape_drv = to_cape_driver(drv); ++ const struct cape_device_id *found_id; ++ ++ found_id = capebus_match_device(cape_drv, cape_dev); ++ if (found_id) ++ return 1; ++ ++ return 0; ++} ++ ++/** ++ * capebus_dev_get - increments the reference count of the capebus ++ * device structure ++ * @dev: the device being referenced ++ * ++ * Each live reference to a device should be refcounted. ++ * ++ * Drivers for cape devices should normally record such references in ++ * their probe() methods, when they bind to a device, and release ++ * them by calling capebus_dev_put(), in their disconnect() methods. ++ * ++ * A pointer to the device with the incremented reference counter is returned. ++ */ ++struct cape_dev *capebus_dev_get(struct cape_dev *dev) ++{ ++ if (dev) ++ get_device(&dev->dev); ++ return dev; ++} ++EXPORT_SYMBOL(capebus_dev_get); ++ ++/** ++ * capebus_dev_put - release a use of the capebus device structure ++ * @dev: device that's been disconnected ++ * ++ * Must be called when a user of a device is finished with it. When the last ++ * user of the device calls this function, the memory of the device is freed. ++ */ ++void capebus_dev_put(struct cape_dev *dev) ++{ ++ if (dev) ++ put_device(&dev->dev); ++} ++EXPORT_SYMBOL(capebus_dev_put); ++ ++static int __init capebus_driver_init(void) ++{ ++ return bus_register(&capebus_bus_type); ++} ++ ++postcore_initcall(capebus_driver_init); ++ ++const struct of_device_id * ++capebus_of_match_device(struct cape_dev *cdev, ++ const char *property, const char *value) ++{ ++ struct cape_bus *bus = cdev->bus; ++ struct device *dev = &cdev->dev; ++ struct device_node *pnode = cape_bus_to_parent_of_node(bus); ++ struct device_node *node; ++ const struct of_device_id *match; ++ const char* cp; ++ int cplen, l; ++ ++ dev_dbg(dev, "Iterating on parent of node " ++ "name='%s' type='%s' full_name='%s'\n", ++ pnode->name, pnode->type, pnode->full_name); ++ ++ match = NULL; ++ for_each_child_of_node(pnode, node) { ++ ++ dev->of_node = node; ++ match = of_match_device(dev->driver->of_match_table, dev); ++ if (!match) ++ goto next_node; ++ ++ cp = of_get_property(node, property, &cplen); ++ if (cp == NULL) ++ goto next_node; ++ ++ while (cplen > 0) { ++ if (of_compat_cmp(cp, value, strlen(value)) == 0) ++ break; ++ l = strlen(cp) + 1; ++ cp += l; ++ cplen -= l; ++ } ++ ++ /* matched */ ++ if (cplen > 0) ++ break; ++next_node: ++ match = NULL; ++ dev->of_node = NULL; ++ } ++ ++ if (match == NULL) { ++ dev_dbg(dev, "Failed to find matching child-node\n"); ++ return NULL; ++ } ++ ++ dev_dbg(dev, "Found matching child node " ++ "name='%s' type='%s' " ++ "full_name='%s' (compatible='%s')\n", ++ node->name, node->type, node->full_name, ++ match->compatible); ++ ++ return match; ++} ++EXPORT_SYMBOL(capebus_of_match_device); ++ ++struct device_node * ++capebus_of_compatible_device_property_match(struct cape_dev *dev, ++ const struct of_device_id *matches, ++ const char *prop, const char *prop_value) ++{ ++ const struct of_device_id *match; ++ struct device_node *node, *cnode; ++ const char* cp; ++ int cplen, l; ++ ++ if (prop == NULL || prop_value == NULL) ++ goto try_non_property; ++ ++ /* at first try secondary match */ ++ for_each_child_of_node(dev->dev.of_node, node) { ++ ++ cp = of_get_property(node, prop, &cplen); ++ if (cp == NULL) ++ continue; ++ ++ while (cplen > 0) { ++ if (of_compat_cmp(cp, prop_value, ++ strlen(prop_value)) == 0) ++ break; ++ l = strlen(cp) + 1; ++ cp += l; ++ cplen -= l; ++ } ++ ++ /* not matched */ ++ if (cplen <= 0) ++ continue; ++ ++ /* now iterate in the children nodes */ ++ for_each_child_of_node(node, cnode) { ++ ++ match = of_match_node(matches, cnode); ++ if (match) { ++ /* release reference to parent, keep this one */ ++ of_node_put(node); ++ return cnode; ++ } ++ } ++ } ++ ++try_non_property: ++ for_each_child_of_node(dev->dev.of_node, node) { ++ ++ match = of_match_node(matches, node); ++ if (match) ++ return node; ++ } ++ ++ return NULL; ++} ++EXPORT_SYMBOL(capebus_of_compatible_device_property_match); ++ ++struct platform_device * ++capebus_of_platform_compatible_device_create(struct cape_dev *dev, ++ const struct of_device_id *matches, ++ const char *pdev_name, ++ const char *prop, const char *prop_value) ++{ ++ struct device_node *node; ++ struct platform_device *pdev; ++ ++ node = capebus_of_compatible_device_property_match(dev, matches, prop, ++ prop_value); ++ if (node == NULL) ++ return ERR_PTR(-ENXIO); ++ ++ pdev = of_platform_device_create(node, pdev_name, dev->bus->dev.parent); ++ ++ /* release the reference to the node */ ++ of_node_put(node); ++ node = NULL; ++ ++ if (pdev == NULL) { ++ dev_err(&dev->dev, "Failed to create platform device '%s'\n", ++ pdev_name); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ return pdev; ++} ++EXPORT_SYMBOL(capebus_of_platform_compatible_device_create); ++ ++struct device_node * ++capebus_of_find_property_node(struct cape_dev *dev, ++ const char *prop, const char *prop_value, ++ const char *name) ++{ ++ struct device_node *node; ++ const char* cp; ++ int cplen, l; ++ struct property *pp; ++ ++ node = NULL; ++ if (prop == NULL || prop_value == NULL) ++ goto find_direct; ++ ++ /* at first try secondary match */ ++ for_each_child_of_node(dev->dev.of_node, node) { ++ ++ cp = of_get_property(node, prop, &cplen); ++ if (cp == NULL) ++ continue; ++ ++ while (cplen > 0) { ++ if (of_compat_cmp(cp, prop_value, ++ strlen(prop_value)) == 0) ++ break; ++ l = strlen(cp) + 1; ++ cp += l; ++ cplen -= l; ++ } ++ ++ /* not matched */ ++ if (cplen <= 0) ++ continue; ++ ++ /* found ? */ ++ pp = of_find_property(node, name, NULL); ++ if (pp != NULL) ++ return node; ++ } ++find_direct: ++ pp = of_find_property(dev->dev.of_node, name, NULL); ++ if (pp == NULL) ++ return NULL; ++ ++ return of_node_get(dev->dev.of_node); ++} ++EXPORT_SYMBOL_GPL(capebus_of_find_property_node); ++ ++struct property * ++capebus_of_find_property(struct cape_dev *dev, ++ const char *prop, const char *prop_value, ++ const char *name, int *lenp) ++{ ++ struct device_node *node; ++ struct property *pp; ++ ++ node = capebus_of_find_property_node(dev, prop, prop_value, name); ++ if (node == NULL) ++ return NULL; ++ ++ pp = of_find_property(node, name, lenp); ++ ++ of_node_put(node); ++ ++ return pp; ++} ++EXPORT_SYMBOL_GPL(capebus_of_find_property); ++ ++const void *capebus_of_get_property(struct cape_dev *dev, ++ const char *prop, const char *prop_value, ++ const char *name, int *lenp) ++{ ++ struct property *pp; ++ ++ pp = capebus_of_find_property(dev, prop, prop_value, name, lenp); ++ return pp ? pp->value : NULL; ++} ++EXPORT_SYMBOL_GPL(capebus_of_get_property); ++ ++/* node exists, but it's not available? make it so */ ++int capebus_of_device_node_enable(struct device_node *node) ++{ ++ struct property *prop; ++ int ret; ++ ++ prop = kzalloc(sizeof(*prop), GFP_KERNEL); ++ if (prop == NULL) ++ goto err_no_prop_mem; ++ ++ prop->name = kstrdup("status", GFP_KERNEL); ++ if (prop->name == NULL) ++ goto err_no_name_mem; ++ ++ prop->value = kstrdup("okay", GFP_KERNEL); ++ if (prop->value == NULL) ++ goto err_no_value_mem; ++ ++ prop->length = strlen(prop->value) + 1; ++ set_bit(OF_DYNAMIC, &prop->_flags); ++ ++ ret = prom_update_property(node, prop); ++ if (ret != 0) ++ goto err_update_failed; ++ ++ return 0; ++ ++err_update_failed: ++ kfree(prop->value); ++err_no_value_mem: ++ kfree(prop->name); ++err_no_name_mem: ++ kfree(prop); ++err_no_prop_mem: ++ return -ENOMEM; ++} ++EXPORT_SYMBOL_GPL(capebus_of_device_node_enable); ++ ++/* Make sure this node is activated (even if it was disabled) */ ++int capebus_of_platform_device_enable(struct device_node *node) ++{ ++ struct platform_device *pdev, *ppdev; ++ int ret; ++ ++ if (of_device_is_available(node)) ++ return 0; ++ ++ ret = capebus_of_device_node_enable(node); ++ if (ret != 0) ++ return ret; ++ ++ /* now we need to find the parent of the node */ ++ ppdev = of_find_device_by_node(node->parent); ++ ++ pdev = of_platform_device_create(node, NULL, ++ ppdev ? &ppdev->dev : NULL); ++ if (IS_ERR_OR_NULL(pdev)) { ++ ret = pdev ? PTR_ERR(pdev) : -ENODEV; ++ return ret; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(capebus_of_platform_device_enable); +diff --git a/drivers/capebus/capebus-probe.c b/drivers/capebus/capebus-probe.c +new file mode 100644 +index 0000000..b46e915 +--- /dev/null ++++ b/drivers/capebus/capebus-probe.c +@@ -0,0 +1,320 @@ ++/* ++ * Capebus bus infrastructure ++ * ++ * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com> ++ * Copyright (C) 2012 Texas Instruments Inc. ++ * ++ * 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 <linux/module.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/of.h> ++#include <linux/of_i2c.h> ++#include <linux/of_device.h> ++#include <linux/pm_runtime.h> ++#include <linux/err.h> ++#include <linux/list.h> ++#include <linux/mutex.h> ++#include <linux/slab.h> ++ ++#include <linux/capebus.h> ++ ++LIST_HEAD(cape_buses); ++EXPORT_SYMBOL(cape_buses); ++ ++DEFINE_MUTEX(cape_buses_mutex); ++EXPORT_SYMBOL(cape_buses_mutex); ++ ++/* ++ * Cape Bus Class ++ */ ++static void release_capebus_dev(struct device *dev) ++{ ++ struct cape_dev *cape_dev = to_cape_dev(dev); ++ ++ kfree(cape_dev); ++} ++ ++static struct class capebus_class = { ++ .name = "capebus", ++ .dev_release = &release_capebus_dev, ++}; ++ ++static int __init capebus_class_init(void) ++{ ++ return class_register(&capebus_class); ++} ++postcore_initcall(capebus_class_init); ++ ++static struct cape_bus *cape_bus_find(const char *name, int busno) ++{ ++ struct cape_bus *bus; ++ int found; ++ ++ if (busno < 0) ++ return NULL; ++ ++ found = 0; ++ cape_bus_for_each(bus) { ++ if (strcmp(name, bus->name) == 0 && bus->busno == busno) { ++ found = 1; ++ break; ++ } ++ } ++ return found ? bus : NULL; ++} ++ ++static int cape_bus_pick_busno(const char *name, int busno) ++{ ++ struct cape_bus *bus; ++ ++ BUG_ON(name == NULL); ++ ++ /* fixed id */ ++ if (busno >= 0) ++ return busno; ++ ++ /* dynamic id */ ++ busno = -1; ++ cape_bus_for_each(bus) { ++ /* name must match */ ++ if (strcmp(name, bus->name) != 0) ++ continue; ++ busno = max(busno, bus->busno); ++ } ++ return busno + 1; ++} ++ ++int cape_bus_register(struct cape_bus *bus, const char *name, int busno, ++ struct device *parent, struct cape_bus_ops *ops) ++{ ++ struct cape_bus *b2; ++ int r; ++ ++ if (name == NULL) ++ return -EINVAL; ++ ++ INIT_LIST_HEAD(&bus->node); ++ INIT_LIST_HEAD(&bus->devices); ++ INIT_LIST_HEAD(&bus->slots); ++ ++ /* do everything under lock */ ++ mutex_lock(&cape_buses_mutex); ++ ++ b2 = cape_bus_find(name, busno); ++ if (b2 != NULL) { ++ if (parent != NULL) ++ dev_err(parent, "capebus %s:%d in use\n", name, busno); ++ else ++ pr_err("capebus %s:%d in use\n", name, busno); ++ r = -EBUSY; ++ goto err_unlock; ++ } ++ bus->name = name; ++ bus->busno = cape_bus_pick_busno(name, busno); ++ bus->ops = ops; ++ ++ bus->dev.class = &capebus_class; ++ bus->dev.parent = parent; ++ dev_set_name(&bus->dev, "%s:%d", bus->name, bus->busno); ++ r = device_register(&bus->dev); ++ if (r != 0) { ++ if (parent != NULL) ++ dev_err(parent, "capebus #%d failed to register dev\n", ++ bus->busno); ++ else ++ pr_err("capebus #%d failed to register dev\n", ++ bus->busno); ++ goto err_unlock; ++ } ++ ++ list_add_tail(&bus->node, &cape_buses); ++ mutex_unlock(&cape_buses_mutex); ++ ++ dev_info(&bus->dev, "Registered\n"); ++ ++ return 0; ++err_unlock: ++ mutex_unlock(&cape_buses_mutex); ++ return r; ++} ++ ++int cape_bus_deregister(struct cape_bus *bus) ++{ ++ return -EINVAL; /* not yet supported */ ++} ++ ++/* must have cape_buses_mutex */ ++struct cape_slot *cape_slot_find(struct cape_bus *bus, int slotno) ++{ ++ struct cape_slot *slot; ++ int found; ++ ++ found = 0; ++ cape_slot_for_each(bus, slot) { ++ if (slot->slotno == slotno) { ++ found = 1; ++ break; ++ } ++ } ++ return found ? slot : NULL; ++} ++ ++/** ++ * cape_bus_release_dev - free a cape device structure when all users ++ * of it are finished. ++ * @dev: device that's been disconnected ++ * ++ * Will be called only by the device core when all users of this cape device are ++ * done. ++ */ ++static void cape_bus_release_dev(struct device *dev) ++{ ++ struct cape_dev *cdev; ++ ++ cdev = to_cape_dev(dev); ++ /* cape_release_capabilities(cdev); TODO */ ++ /* cape_release_of_node(cdev); TODO */ ++ kfree(cdev); ++} ++ ++/* mutex lock must be held */ ++static struct cape_dev *cape_bus_scan_slot(struct cape_slot *slot) ++{ ++ struct cape_bus *bus = slot->bus; ++ struct cape_dev *dev; ++ const struct cape_device_id *id; ++ ++ /* get the ID (if a device exists) */ ++ id = bus->ops->get_dev_id(slot); ++ if (id == NULL) ++ return ERR_PTR(-ENODEV); ++ ++ /* slot must not have a device yet */ ++ dev = slot->dev; ++ if (dev == NULL) { ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (dev == NULL) { ++ dev_info(&bus->dev, "Failed to allocate cape device " ++ "for slot #%d\n", slot->slotno); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ INIT_LIST_HEAD(&dev->bus_list); ++ dev->bus = bus; ++ dev->slot = slot; ++ } ++ ++ dev->id = id; ++ dev->text_id = bus->ops->get_text_dev_id(slot); ++ ++ /* capebus_set_of_node(dev); TODO */ ++ ++ return dev; ++} ++ ++int cape_bus_scan_one_slot(struct cape_bus *bus, struct cape_slot *slot) ++{ ++ struct cape_dev *dev; ++ int r; ++ ++ mutex_lock(&cape_buses_mutex); ++ ++ dev = slot->dev; ++ if (dev == NULL) { ++ ++ dev = cape_bus_scan_slot(slot); ++ if (IS_ERR(dev)) { ++ r = PTR_ERR(dev); ++ goto err_out; ++ } ++ ++ dev_info(&bus->dev, "Slot #%d id='%s'\n", slot->slotno, ++ dev->text_id ? dev->text_id : ""); ++ ++ slot->dev = dev; ++ ++ dev->dev.release = cape_bus_release_dev; ++ dev->dev.parent = &dev->bus->dev; ++ dev->dev.bus = &capebus_bus_type; ++ dev_set_name(&dev->dev, "%s-%d:%d", ++ dev->bus->name, dev->bus->busno, ++ dev->slot->slotno); ++ ++ list_add_tail(&dev->bus_list, &bus->devices); ++ ++ } else { ++ dev_info(&bus->dev, "Slot #%d id='%s' - rescan\n", slot->slotno, ++ dev->text_id ? dev->text_id : ""); ++ ++ if (dev->added) { ++ r = -EEXIST; ++ goto err_out; ++ } ++ } ++ ++ r = device_register(&dev->dev); ++ if (r != 0) { ++ dev_info(&bus->dev, "Slot #%d id='%s' - " ++ "Failed to register\n", ++ slot->slotno, ++ dev->text_id ? dev->text_id : ""); ++ r = 0; ++ } else { ++ if (dev->bus->ops->dev_registered) ++ dev->bus->ops->dev_registered(dev); ++ } ++ ++err_out: ++ mutex_unlock(&cape_buses_mutex); ++ ++ return r; ++} ++ ++int cape_bus_register_slot(struct cape_bus *bus, struct cape_slot *slot, ++ int slotno) ++{ ++ struct cape_slot *s2; ++ int r; ++ ++ r = 0; ++ ++ /* invalid (slot must always be numbered - no hotplug) */ ++ if (slotno < 0) { ++ dev_err(&bus->dev, "Slot registration #%d failed\n", slotno); ++ return -EINVAL; ++ } ++ ++ mutex_lock(&cape_buses_mutex); ++ s2 = cape_slot_find(bus, slotno); ++ if (s2 != NULL) { ++ dev_err(&bus->dev, "Slot #%d already exists\n", slotno); ++ mutex_unlock(&cape_buses_mutex); ++ return -EINVAL; ++ } ++ ++ INIT_LIST_HEAD(&slot->node); ++ slot->bus = bus; ++ list_add(&slot->node, &bus->slots); ++ slot->slotno = slotno; ++ slot->dev = NULL; ++ mutex_unlock(&cape_buses_mutex); ++ ++ dev_info(&bus->dev, "Slot #%d registered\n", slot->slotno); ++ ++ return cape_bus_scan_one_slot(bus, slot); ++} +diff --git a/drivers/capebus/capebus-sysfs.c b/drivers/capebus/capebus-sysfs.c +new file mode 100644 +index 0000000..81c21fe +--- /dev/null ++++ b/drivers/capebus/capebus-sysfs.c +@@ -0,0 +1,52 @@ ++/* ++ * drivers/capebus/capebus-sysfs.c ++ * ++ * sysfs for capebus devices ++ * ++ * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com> ++ * Copyright (C) 2012 Texas Instruments Inc. ++ * ++ * 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. ++ * ++ * Modeled after PCI's pci-sysfs.c ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/stat.h> ++#include <linux/export.h> ++#include <linux/fs.h> ++#include <linux/slab.h> ++#include <linux/pm_runtime.h> ++ ++#include <linux/capebus.h> ++ ++static ssize_t id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct cape_dev *cdev; ++ ++ cdev = to_cape_dev(dev); ++ return sprintf(buf, "%s\n", cdev->text_id); ++} ++ ++struct device_attribute capebus_dev_attrs[] = { ++ __ATTR_RO(id), ++ __ATTR_NULL, ++}; ++ ++struct bus_attribute capebus_bus_attrs[] = { ++ __ATTR_NULL ++}; +diff --git a/include/linux/capebus.h b/include/linux/capebus.h +new file mode 100644 +index 0000000..7524401 +--- /dev/null ++++ b/include/linux/capebus.h +@@ -0,0 +1,298 @@ ++/* ++ * capebus.h ++ * ++ * Cape bus defines and function prototypes ++ * ++ * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com> ++ * Copyright (C) 2012 Texas Instruments Inc. ++ * ++ * 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_CAPEBUS_H ++#define LINUX_CAPEBUS_H ++ ++#include <linux/list.h> ++#include <linux/device.h> ++#include <linux/spinlock.h> ++#include <linux/types.h> ++#include <linux/atomic.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++ ++struct cape_device_id { ++ const char *cntrlboard; /* controlling board; i.e. "beaglebone" */ ++ int len; /* opaque addressing data */ ++ const void *data; ++}; ++ ++struct cape_dev; ++struct cape_bus; ++struct cape_slot; ++ ++struct cape_slot { ++ struct list_head node; ++ struct cape_bus *bus; /* the bus this slot is on */ ++ int slotno; /* index of this slot */ ++ struct cape_dev *dev; /* the device (if found) */ ++}; ++ ++struct cape_driver { ++ struct list_head node; ++ int (*probe)(struct cape_dev *dev, const struct cape_device_id *id); ++ void (*remove)(struct cape_dev *dev); ++ int (*suspend) (struct cape_dev *dev, pm_message_t state); ++ int (*suspend_late) (struct cape_dev *dev, pm_message_t state); ++ int (*resume_early) (struct cape_dev *dev); ++ int (*resume) (struct cape_dev *dev); ++ void (*shutdown) (struct cape_dev *dev); ++ struct device_driver driver; ++}; ++ ++/* ++ * capebus_register_driver must be a macro so that ++ * KBUILD_MODNAME can be expanded ++ */ ++#define capebus_register_driver(driver) \ ++ __capebus_register_driver(driver, THIS_MODULE, KBUILD_MODNAME) ++ ++int __capebus_register_driver(struct cape_driver *drv, struct module *owner, ++ const char *mod_name); ++ ++void capebus_unregister_driver(struct cape_driver *dev); ++ ++/** ++ * module_capebus_driver() - Helper macro for registering a capebus driver ++ * @__capebus_driver: capebus_driver struct ++ * ++ * Helper macro for capebus drivers which do not do anything special in module ++ * init/exit. This eliminates a lot of boilerplate. Each module may only ++ * use this macro once, and calling it replaces module_init() and module_exit() ++ */ ++#define module_capebus_driver(__capebus_driver) \ ++ module_driver(__capebus_driver, capebus_register_driver, \ ++ capebus_unregister_driver) ++ ++#define to_cape_driver(n) container_of(n, struct cape_driver, driver) ++ ++struct cape_bus_ops { ++ const struct cape_device_id *(*get_dev_id)(struct cape_slot *slot); ++ const char *(*get_text_dev_id)(struct cape_slot *slot); ++ int (*dev_probed)(struct cape_dev *dev); /* probed succesfully */ ++ void (*dev_removed)(struct cape_dev *dev); /* removed */ ++ int (*dev_registered)(struct cape_dev *dev); /* registered OK */ ++}; ++ ++struct cape_bus { ++ struct list_head node; ++ const char *name; ++ struct list_head devices; ++ struct cape_dev *self; ++ struct list_head slots; ++ struct cape_bus_ops *ops; ++ int busno; ++ struct device dev; ++ /* TODO: resources.... */ ++}; ++ ++#define to_cape_bus(n) container_of(n, struct cape_bus, dev) ++ ++#define cape_bus_to_parent_of_node(n) ((n)->dev.parent->of_node) ++ ++struct cape_dev { ++ struct list_head bus_list; /* node in per-bus list */ ++ struct cape_bus *bus; /* bus this device is on */ ++ struct cape_slot *slot; /* cape slot of this device */ ++ struct cape_driver *driver; /* driver of this device */ ++ struct device dev; ++ atomic_t enable_cnt; /* capebus_enable_device */ ++ /* has been called */ ++ const struct cape_device_id *id; ++ const char *text_id; ++ unsigned int added : 1; /* device has been added */ ++ void *drv_priv; /* driver private data */ ++}; ++ ++#define to_cape_dev(n) container_of(n, struct cape_dev, dev) ++ ++struct cape_dev *capebus_dev_get(struct cape_dev *dev); ++void capebus_dev_put(struct cape_dev *dev); ++ ++/* must have cape_buses_mutex */ ++#define cape_bus_for_each(_bus) \ ++ list_for_each_entry(_bus, &cape_buses, node) ++ ++#define cape_bus_for_each_safe(_bus, _busn) \ ++ list_for_each_entry_safe(_bus, _busn, &cape_buses, node) ++ ++int cape_bus_register(struct cape_bus *bus, const char *name, int busno, ++ struct device *parent, struct cape_bus_ops *ops); ++ ++/* must have cape_buses_mutex */ ++#define cape_slot_for_each(_bus, _slot) \ ++ list_for_each_entry(_slot, &(_bus)->slots, node) ++ ++#define cape_slot_for_each_safe(_bus, _slot, _slotn) \ ++ list_for_each_entry_safe(_slot, _slotn, &(_bus)->slots, node) ++ ++int cape_bus_register_slot(struct cape_bus *bus, ++ struct cape_slot *slot, int slotno); ++ ++int cape_bus_scan_one_slot(struct cape_bus *bus, struct cape_slot *slot); ++int cape_bus_scan(struct cape_bus *bus); ++ ++extern struct list_head cape_buses; ++extern struct mutex cape_buses_mutex; ++ ++static inline int capebus_is_enabled(struct cape_dev *cdev) ++{ ++ return atomic_read(&cdev->enable_cnt) > 0; ++} ++ ++static inline int capebus_enable_device(struct cape_dev *cdev) ++{ ++ if (atomic_add_return(1, &cdev->enable_cnt) > 1) ++ return 0; /* already enabled */ ++ ++ /* XXX do enable */ ++ ++ return 0; ++} ++ ++static inline void capebus_disable_device(struct cape_dev *cdev) ++{ ++ if (atomic_sub_return(1, &cdev->enable_cnt) != 0) ++ return; ++ ++ /* callback to disable device? */ ++} ++ ++static inline int capebus_enable_wake(struct cape_dev *dev, int what) ++{ ++ return 0; ++} ++ ++extern struct device_attribute capebus_dev_attrs[]; ++extern struct bus_attribute capebus_bus_attrs[]; ++ ++extern struct bus_type capebus_bus_type; ++ ++const struct of_device_id * ++capebus_of_match_device(struct cape_dev *cdev, ++ const char *property, const char *value); ++ ++struct device_node * ++capebus_of_compatible_device_property_match(struct cape_dev *dev, ++ const struct of_device_id *matches, ++ const char *prop, const char *prop_value); ++ ++struct platform_device * ++capebus_of_platform_compatible_device_create(struct cape_dev *dev, ++ const struct of_device_id *matches, ++ const char *pdev_name, ++ const char *prop, const char *prop_value); ++ ++/* of tree support */ ++ ++struct device_node * ++capebus_of_find_property_node(struct cape_dev *dev, ++ const char *prop, const char *prop_value, ++ const char *name); ++ ++struct property * ++capebus_of_find_property(struct cape_dev *dev, ++ const char *prop, const char *prop_value, ++ const char *name, int *lenp); ++ ++const void *capebus_of_get_property(struct cape_dev *dev, ++ const char *prop, const char *prop_value, ++ const char *name, int *lenp); ++ ++static inline int capebus_of_property_read_u32_array(struct cape_dev *dev, ++ const char *prop, const char *prop_value, ++ const char *name, u32 *out_values, size_t sz) ++{ ++ struct device_node *node; ++ int ret; ++ ++ node = capebus_of_find_property_node(dev, prop, prop_value, name); ++ ret = of_property_read_u32_array(node, name, out_values, sz); ++ of_node_put(node); ++ return ret; ++} ++ ++static inline int capebus_of_property_read_u32(struct cape_dev *dev, ++ const char *prop, const char *prop_value, ++ const char *name, u32 *out_value) ++{ ++ return capebus_of_property_read_u32_array(dev, prop, ++ prop_value, name, out_value, 1); ++} ++ ++static inline bool capebus_of_property_read_bool(struct cape_dev *dev, ++ const char *prop, const char *prop_value, ++ const char *name) ++{ ++ struct device_node *node; ++ bool ret; ++ ++ node = capebus_of_find_property_node(dev, prop, prop_value, name); ++ ret = of_property_read_bool(node, name); ++ of_node_put(node); ++ return ret; ++} ++ ++static inline int capebus_of_property_read_string(struct cape_dev *dev, ++ const char *prop, const char *prop_value, ++ const char *name, const char **out_string) ++{ ++ struct device_node *node; ++ int ret; ++ ++ node = capebus_of_find_property_node(dev, prop, prop_value, name); ++ ret = of_property_read_string(node, name, out_string); ++ of_node_put(node); ++ return ret; ++} ++ ++static inline int capebus_of_property_read_string_index(struct cape_dev *dev, ++ const char *prop, const char *prop_value, ++ const char *name, int index, const char **out_string) ++{ ++ struct device_node *node; ++ int ret; ++ ++ node = capebus_of_find_property_node(dev, prop, prop_value, name); ++ ret = of_property_read_string_index(node, name, index, out_string); ++ of_node_put(node); ++ return ret; ++} ++ ++static inline int capebus_of_property_read_u64(struct cape_dev *dev, ++ const char *prop, const char *prop_value, ++ const char *name, u64 *out_value) ++{ ++ struct device_node *node; ++ int ret; ++ ++ node = capebus_of_find_property_node(dev, prop, prop_value, name); ++ ret = of_property_read_u64(node, name, out_value); ++ of_node_put(node); ++ return ret; ++} ++ ++int capebus_of_device_node_enable(struct device_node *node); ++int capebus_of_platform_device_enable(struct device_node *node); ++ ++#endif diff --git a/patches/linux-3.7-rc6/0134-capebus-Add-beaglebone-board-support.patch b/patches/linux-3.7-rc6/0134-capebus-Add-beaglebone-board-support.patch new file mode 100644 index 0000000..edf46cb --- /dev/null +++ b/patches/linux-3.7-rc6/0134-capebus-Add-beaglebone-board-support.patch @@ -0,0 +1,1955 @@ +From 2f38e4b945ff8671b3a8341872188cfd0b5ff1f2 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Tue, 30 Oct 2012 21:07:50 +0200 +Subject: [PATCH] capebus: Add beaglebone board support + +--- + drivers/capebus/boards/Kconfig | 6 + + drivers/capebus/boards/Makefile | 3 + + drivers/capebus/boards/capebus-bone-generic.c | 237 +++++++ + drivers/capebus/boards/capebus-bone-pdevs.c | 602 ++++++++++++++++ + drivers/capebus/boards/capebus-bone.c | 931 +++++++++++++++++++++++++ + include/linux/capebus/capebus-bone.h | 120 ++++ + 6 files changed, 1899 insertions(+) + create mode 100644 drivers/capebus/boards/Kconfig + create mode 100644 drivers/capebus/boards/Makefile + create mode 100644 drivers/capebus/boards/capebus-bone-generic.c + create mode 100644 drivers/capebus/boards/capebus-bone-pdevs.c + create mode 100644 drivers/capebus/boards/capebus-bone.c + create mode 100644 include/linux/capebus/capebus-bone.h + +diff --git a/drivers/capebus/boards/Kconfig b/drivers/capebus/boards/Kconfig +new file mode 100644 +index 0000000..76b0f94 +--- /dev/null ++++ b/drivers/capebus/boards/Kconfig +@@ -0,0 +1,6 @@ ++config CAPEBUS_BONE_CONTROLLER ++ bool "Beaglebone capebus board controller" ++ depends on CAPEBUS && ARCH_OMAP2PLUS && OF && I2C ++ default n ++ help ++ "Select this to enable the beaglebone capebus board controller" +diff --git a/drivers/capebus/boards/Makefile b/drivers/capebus/boards/Makefile +new file mode 100644 +index 0000000..9048231 +--- /dev/null ++++ b/drivers/capebus/boards/Makefile +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_CAPEBUS_BONE_CONTROLLER) += capebus-bone.o \ ++ capebus-bone-pdevs.o \ ++ capebus-bone-generic.o \ +diff --git a/drivers/capebus/boards/capebus-bone-generic.c b/drivers/capebus/boards/capebus-bone-generic.c +new file mode 100644 +index 0000000..b1b79eb +--- /dev/null ++++ b/drivers/capebus/boards/capebus-bone-generic.c +@@ -0,0 +1,237 @@ ++/* ++ * TI Beaglebone capebus controller - Generic devices ++ * ++ * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com> ++ * Copyright (C) 2012 Texas Instruments Inc. ++ * ++ * 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 <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/string.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/bitops.h> ++#include <linux/err.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_gpio.h> ++#include <video/da8xx-fb.h> ++#include <linux/pinctrl/pinctrl.h> ++#include <linux/pinctrl/pinmux.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/atomic.h> ++#include <linux/clk.h> ++#include <asm/barrier.h> ++#include <plat/clock.h> ++#include <plat/omap_device.h> ++#include <linux/clkdev.h> ++#include <linux/input/ti_am335x_tsc.h> ++#include <linux/platform_data/ti_am335x_adc.h> ++#include <linux/mfd/ti_am335x_tscadc.h> ++ ++#include <linux/capebus/capebus-bone.h> ++ ++int bone_capebus_probe_prolog(struct cape_dev *dev, ++ const struct cape_device_id *id) ++{ ++ char boardbuf[33]; ++ char versionbuf[5]; ++ const char *board_name; ++ const char *version; ++ const struct of_device_id *match; ++ struct pinctrl *pinctrl; ++ ++ /* get the board name (also matches the cntrlboard before checking) */ ++ board_name = bone_capebus_id_get_field(id, BONE_CAPEBUS_BOARD_NAME, ++ boardbuf, sizeof(boardbuf)); ++ if (board_name == NULL) ++ return -ENODEV; ++ ++ /* match compatible? */ ++ match = capebus_of_match_device(dev, "board-name", board_name); ++ if (match == NULL) ++ return -ENODEV; ++ ++ /* get the board version */ ++ version = bone_capebus_id_get_field(id, BONE_CAPEBUS_VERSION, ++ versionbuf, sizeof(versionbuf)); ++ if (version == NULL) ++ return -ENODEV; ++ ++ pinctrl = devm_pinctrl_get_select_default(&dev->dev); ++ if (IS_ERR(pinctrl)) ++ dev_warn(&dev->dev, ++ "pins are not configured from the driver\n"); ++ ++ dev_info(&dev->dev, "%s: V=%s '%s'\n", board_name, ++ version, match->compatible); ++ ++ return 0; ++} ++EXPORT_SYMBOL(bone_capebus_probe_prolog); ++ ++static const struct bone_capebus_generic_device_data gendevs[] = { ++ { ++ .name = "leds", ++ .of_match = (const struct of_device_id []) { ++ { .compatible = "gpio-leds", }, { }, ++ }, ++ .units = 0, /* no limit */ ++ }, { ++ .name = "tps-bl", ++ .of_match = (const struct of_device_id []) { ++ { .compatible = "tps65217-backlight", }, { }, ++ }, ++ .units = 0, /* no limit */ ++ }, { ++ .name = "keys", ++ .of_match = (const struct of_device_id []) { ++ { .compatible = "gpio-keys", }, { }, ++ }, ++ .units = 0, /* no limit */ ++ }, { ++ .name = "tscadc", ++ .of_match = (const struct of_device_id []) { ++ { .compatible = "ti-tscadc-dt", }, { }, ++ }, ++ .units = 1, ++ }, { ++ .name = "lcdc", ++ .of_match = (const struct of_device_id []) { ++ { .compatible = "da8xx-dt", }, { }, ++ }, ++ .units = 1, ++ },{ ++ .name = "i2c-dt", ++ .of_match = (const struct of_device_id []) { ++ { .compatible = "i2c-dt", }, { }, ++ }, ++ .units = 0, ++ }, { ++ .name = "w1-gpio", ++ .of_match = (const struct of_device_id []) { ++ { .compatible = "w1-gpio", }, { }, ++ }, ++ .units = 0, ++ }, { ++ .name = "pwm-backlight", ++ .of_match = (const struct of_device_id []) { ++ { .compatible = "pwm-backlight", }, { }, ++ }, ++ .units = 0, /* no limit */ ++ }, { ++ .name = "spi-dt", ++ .of_match = (const struct of_device_id []) { ++ { .compatible = "spi-dt", }, { }, ++ }, ++ .units = 0, /* no limit */ ++ } ++}; ++ ++struct bone_capebus_generic_info * ++bone_capebus_probe_generic(struct cape_dev *dev, ++ const struct cape_device_id *id) ++{ ++ struct bone_capebus_generic_info *info; ++ char boardbuf[33]; ++ char versionbuf[5]; ++ const char *board_name; ++ const char *version; ++ struct platform_device *pdev; ++ const struct bone_capebus_generic_device_data *dd; ++ struct bone_capebus_generic_device_entry *de; ++ int i; ++ ++ /* get the board name (also matches the cntrlboard before checking) */ ++ board_name = bone_capebus_id_get_field(id, BONE_CAPEBUS_BOARD_NAME, ++ boardbuf, sizeof(boardbuf)); ++ /* get the board version */ ++ version = bone_capebus_id_get_field(id, BONE_CAPEBUS_VERSION, ++ versionbuf, sizeof(versionbuf)); ++ ++ /* should never happen, but it doesn't hurt to play it safe */ ++ if (board_name == NULL || version == NULL) ++ return ERR_PTR(-ENODEV); ++ ++ info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) { ++ dev_err(&dev->dev, "Failed to allocate info\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ info->dev = dev; ++ INIT_LIST_HEAD(&info->pdev_list); ++ ++ /* iterate over the supported devices */ ++ for (i = 0, dd = gendevs; i < ARRAY_SIZE(gendevs); i++, dd++) { ++ ++ pdev = capebus_of_platform_compatible_device_create(dev, ++ dd->of_match, dd->name, "version", version); ++ ++ /* node not found (mostly harmless) */ ++ if (IS_ERR(pdev) && PTR_ERR(pdev) == -ENXIO) { ++ /* TODO: deal with required nodes */ ++ continue; ++ } ++ ++ /* failed to create due to an error; fatal */ ++ if (IS_ERR_OR_NULL(pdev)) { ++ dev_err(&dev->dev, "failed to create device %s\n", ++ dd->name); ++ goto err_fail; ++ } ++ ++ de = devm_kzalloc(&dev->dev, sizeof(*de), GFP_KERNEL); ++ if (de == NULL) { ++ dev_err(&dev->dev, "failed to allocate entry for %s\n", ++ dd->name); ++ goto err_fail; ++ } ++ ++ /* add it to the list */ ++ de->data = dd; ++ de->pdev = pdev; ++ list_add_tail(&de->node, &info->pdev_list); ++ } ++ ++ return info; ++ ++err_fail: ++ bone_capebus_remove_generic(info); ++ return NULL; ++} ++EXPORT_SYMBOL(bone_capebus_probe_generic); ++ ++void bone_capebus_remove_generic(struct bone_capebus_generic_info *info) ++{ ++ struct list_head *lh, *lhn; ++ struct bone_capebus_generic_device_entry *de; ++ ++ if (info == NULL || info->dev == NULL) ++ return; ++ ++ list_for_each_safe(lh, lhn, &info->pdev_list) { ++ de = list_entry(lh, struct bone_capebus_generic_device_entry, ++ node); ++ list_del(lh); ++ platform_device_unregister(de->pdev); ++ devm_kfree(&info->dev->dev, de); ++ } ++ devm_kfree(&info->dev->dev, info); ++} ++EXPORT_SYMBOL(bone_capebus_remove_generic); +diff --git a/drivers/capebus/boards/capebus-bone-pdevs.c b/drivers/capebus/boards/capebus-bone-pdevs.c +new file mode 100644 +index 0000000..a55aad6 +--- /dev/null ++++ b/drivers/capebus/boards/capebus-bone-pdevs.c +@@ -0,0 +1,602 @@ ++/* ++ * TI Beaglebone capebus controller - Platform adapters ++ * ++ * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com> ++ * Copyright (C) 2012 Texas Instruments Inc. ++ * ++ * 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 <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/string.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/bitops.h> ++#include <linux/err.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_gpio.h> ++#include <video/da8xx-fb.h> ++#include <linux/pinctrl/pinctrl.h> ++#include <linux/pinctrl/pinmux.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/atomic.h> ++#include <linux/clk.h> ++#include <asm/barrier.h> ++#include <plat/clock.h> ++#include <plat/omap_device.h> ++#include <linux/clkdev.h> ++#include <linux/input/ti_am335x_tsc.h> ++#include <linux/platform_data/ti_am335x_adc.h> ++#include <linux/mfd/ti_am335x_tscadc.h> ++#include <linux/i2c.h> ++#include <linux/of_i2c.h> ++#include <linux/spi/spi.h> ++ ++#include <linux/capebus/capebus-bone.h> ++ ++#if defined(CONFIG_FB_DA8XX) || defined(CONFIG_FB_DA8XX_MODULE) ++ ++struct da8xx_priv { ++ struct da8xx_lcdc_platform_data lcd_pdata; ++ struct lcd_ctrl_config lcd_cfg; ++ struct display_panel lcd_panel; ++ struct platform_device *lcdc_pdev; ++ struct omap_hwmod *lcdc_oh; ++ struct resource lcdc_res[1]; ++ int power_dn_gpio; ++}; ++ ++static const struct of_device_id of_da8xx_dt_match[] = { ++ { .compatible = "da8xx-dt", }, ++ {}, ++}; ++ ++static int __devinit da8xx_dt_probe(struct platform_device *pdev) ++{ ++ struct da8xx_priv *priv; ++ struct clk *disp_pll; ++ struct pinctrl *pinctrl; ++ u32 disp_pll_val; ++ const char *panel_type; ++ int ret = -EINVAL; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (priv == NULL) { ++ dev_err(&pdev->dev, "Failed to allocate priv\n"); ++ return -ENOMEM; ++ } ++ priv->power_dn_gpio = -1; ++ ++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev); ++ if (IS_ERR(pinctrl)) ++ dev_warn(&pdev->dev, ++ "pins are not configured from the driver\n"); ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "disp-pll", &disp_pll_val); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to read disp-pll property\n"); ++ return ret; ++ } ++ ++ ret = of_property_read_string(pdev->dev.of_node, "panel-type", &panel_type); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to read panel-type property\n"); ++ return ret; ++ } ++ ++ /* conf_disp_pll(disp_pll); */ ++ disp_pll = clk_get(NULL, "dpll_disp_ck"); ++ if (IS_ERR(disp_pll)) { ++ dev_err(&pdev->dev, "Cannot clk_get disp_pll\n"); ++ return PTR_ERR(disp_pll); ++ } ++ ret = clk_set_rate(disp_pll, disp_pll_val); ++ clk_put(disp_pll); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to set disp_pll\n"); ++ return ret; ++ } ++ ++ ret = of_get_named_gpio_flags(pdev->dev.of_node, "powerdn-gpio", ++ 0, NULL); ++ if (IS_ERR_VALUE(ret)) { ++ dev_info(&pdev->dev, "No power down GPIO\n"); ++ } else { ++ priv->power_dn_gpio = ret; ++ ++ ret = devm_gpio_request(&pdev->dev, priv->power_dn_gpio, "bone-dvi-cape:DVI_PDN"); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to gpio_request\n"); ++ return ret; ++ } ++ ++ ret = gpio_direction_output(priv->power_dn_gpio, 1); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to set powerdn to 1\n"); ++ return ret; ++ } ++ } ++ ++ /* display_panel */ ++ priv->lcd_panel.panel_type = QVGA; ++ priv->lcd_panel.max_bpp = 16; ++ priv->lcd_panel.min_bpp = 16; ++ priv->lcd_panel.panel_shade = COLOR_ACTIVE; ++ ++ /* lcd_ctrl_config */ ++ priv->lcd_cfg.p_disp_panel = &priv->lcd_panel; ++ priv->lcd_cfg.ac_bias = 255; ++ priv->lcd_cfg.ac_bias_intrpt = 0; ++ priv->lcd_cfg.dma_burst_sz = 16; ++ priv->lcd_cfg.bpp = 16; ++ priv->lcd_cfg.fdd = 0x80; ++ priv->lcd_cfg.tft_alt_mode = 0; ++ priv->lcd_cfg.stn_565_mode = 0; ++ priv->lcd_cfg.mono_8bit_mode = 0; ++ priv->lcd_cfg.invert_line_clock = 1; ++ priv->lcd_cfg.invert_frm_clock = 1; ++ priv->lcd_cfg.sync_edge = 0; ++ priv->lcd_cfg.sync_ctrl = 1; ++ priv->lcd_cfg.raster_order = 0; ++ ++ /* da8xx_lcdc_platform_data */ ++ strcpy(priv->lcd_pdata.manu_name, "BBToys"); ++ priv->lcd_pdata.controller_data = &priv->lcd_cfg; ++ strcpy(priv->lcd_pdata.type, panel_type); ++ ++ priv->lcdc_oh = omap_hwmod_lookup("lcdc"); ++ if (priv->lcdc_oh == NULL) { ++ dev_err(&pdev->dev, "Failed to lookup omap_hwmod lcdc\n"); ++ return -ENODEV; ++ } ++ ++ priv->lcdc_pdev = omap_device_build("da8xx_lcdc", 0, priv->lcdc_oh, ++ &priv->lcd_pdata, ++ sizeof(struct da8xx_lcdc_platform_data), ++ NULL, 0, 0); ++ if (priv->lcdc_pdev == NULL) { ++ dev_err(&pdev->dev, "Failed to build LCDC device\n"); ++ return -ENODEV; ++ } ++ ++ dev_info(&pdev->dev, "Registered bone LCDC OK.\n"); ++ ++ platform_set_drvdata(pdev, priv); ++ ++ return 0; ++} ++ ++static int __devexit da8xx_dt_remove(struct platform_device *pdev) ++{ ++ return -EINVAL; /* not supporting removal yet */ ++} ++ ++static struct platform_driver da8xx_dt_driver = { ++ .probe = da8xx_dt_probe, ++ .remove = __devexit_p(da8xx_dt_remove), ++ .driver = { ++ .name = "da8xx-dt", ++ .owner = THIS_MODULE, ++ .of_match_table = of_da8xx_dt_match, ++ }, ++}; ++ ++#endif ++ ++#if defined(CONFIG_MFD_TI_AM335X_TSCADC) || defined(CONFIG_MFD_TI_AM335X_TSCADC_MODULE) ++ ++struct ti_tscadc_priv { ++ struct omap_hwmod *tsc_oh; ++ struct tsc_data tsc_data; ++ struct adc_data adc_data; ++ struct mfd_tscadc_board tscadc_data; ++ struct platform_device *tscadc_pdev; ++}; ++ ++static const struct of_device_id of_ti_tscadc_dt_match[] = { ++ { .compatible = "ti-tscadc-dt", }, ++ {}, ++}; ++ ++static int __devinit ti_tscadc_dt_probe(struct platform_device *pdev) ++{ ++ struct ti_tscadc_priv *priv; ++ struct pinctrl *pinctrl; ++ u32 val; ++ int ret; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (priv == NULL) { ++ dev_err(&pdev->dev, "Failed to allocate priv\n"); ++ return -ENOMEM; ++ } ++ ++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev); ++ if (IS_ERR(pinctrl)) ++ dev_warn(&pdev->dev, ++ "pins are not configured from the driver\n"); ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "tsc-wires", &val); ++ if (ret != 0) { ++ dev_info(&pdev->dev, "no tsc-wires property; disabling TSC\n"); ++ val = 0; ++ } ++ priv->tsc_data.wires = val; ++ ++ if (priv->tsc_data.wires > 0) { ++ ret = of_property_read_u32(pdev->dev.of_node, ++ "tsc-x-plate-resistance", &val); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to read " ++ "tsc-x-plate-resistance property\n"); ++ return ret; ++ } ++ priv->tsc_data.x_plate_resistance = val; ++ ++ ret = of_property_read_u32(pdev->dev.of_node, ++ "tsc-steps", &val); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to read " ++ "tsc-steps property\n"); ++ return ret; ++ } ++ priv->tsc_data.steps_to_configure = val; ++ } ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "adc-channels", &val); ++ if (ret != 0) { ++ dev_info(&pdev->dev, "No adc-channels property; disabling adc\n"); ++ val = 0; ++ } ++ priv->adc_data.adc_channels = val; ++ ++ priv->tscadc_data.tsc_init = &priv->tsc_data; ++ priv->tscadc_data.adc_init = &priv->adc_data; ++ ++ priv->tsc_oh = omap_hwmod_lookup("adc_tsc"); ++ if (priv->tsc_oh == NULL) { ++ dev_err(&pdev->dev, "Could not lookup HWMOD %s\n", "adc_tsc"); ++ return -ENODEV; ++ } ++ ++ priv->tscadc_pdev = omap_device_build("ti_tscadc", -1, priv->tsc_oh, ++ &priv->tscadc_data, sizeof(priv->tscadc_data), ++ NULL, 0, 0); ++ if (priv->tscadc_pdev == NULL) { ++ dev_err(&pdev->dev, "Could not create tsc_adc device\n"); ++ return -ENODEV; ++ } ++ ++ dev_info(&pdev->dev, "TI tscadc pdev created OK\n"); ++ ++ platform_set_drvdata(pdev, priv); ++ ++ return 0; ++} ++ ++static int __devexit ti_tscadc_dt_remove(struct platform_device *pdev) ++{ ++ return -EINVAL; /* not supporting removal yet */ ++} ++ ++static struct platform_driver ti_tscadc_dt_driver = { ++ .probe = ti_tscadc_dt_probe, ++ .remove = __devexit_p(ti_tscadc_dt_remove), ++ .driver = { ++ .name = "ti_tscadc-dt", ++ .owner = THIS_MODULE, ++ .of_match_table = of_ti_tscadc_dt_match, ++ }, ++}; ++ ++#endif ++ ++struct i2c_priv { ++ struct i2c_adapter *i2c_adapter; ++ phandle parent_handle; ++}; ++ ++static const struct of_device_id of_i2c_dt_match[] = { ++ { .compatible = "i2c-dt", }, ++ {}, ++}; ++ ++static int __devinit i2c_dt_probe(struct platform_device *pdev) ++{ ++ struct i2c_priv *priv = NULL; ++ int ret = -EINVAL; ++ struct device_node *adap_node; ++ u32 val; ++ ++ if (pdev->dev.of_node == NULL) { ++ dev_err(&pdev->dev, "Only support OF case\n"); ++ return -ENOMEM; ++ } ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (priv == NULL) { ++ dev_err(&pdev->dev, "Failed to allocate priv\n"); ++ return -ENOMEM; ++ } ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "parent", &val); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to find parent property\n"); ++ goto err_prop_fail; ++ } ++ priv->parent_handle = val; ++ ++ adap_node = of_find_node_by_phandle(priv->parent_handle); ++ if (adap_node == NULL) { ++ dev_err(&pdev->dev, "Failed to find i2c adapter node\n"); ++ ret = -EINVAL; ++ goto err_node_fail; ++ } ++ ++ ret = capebus_of_platform_device_enable(adap_node); ++ if (ret != 0) { ++ dev_info(&pdev->dev, "I2C adapter platform device failed " ++ "to enable\n"); ++ goto err_enable_fail; ++ } ++ ++ priv->i2c_adapter = of_find_i2c_adapter_by_node(adap_node); ++ if (priv->i2c_adapter == NULL) { ++ dev_err(&pdev->dev, "Failed to find i2c adapter node\n"); ++ ret = -EINVAL; ++ goto err_adap_fail; ++ } ++ ++ of_i2c_register_node_devices(priv->i2c_adapter, pdev->dev.of_node); ++ ++ of_node_put(adap_node); ++ ++ dev_info(&pdev->dev, "Registered bone I2C OK.\n"); ++ ++ platform_set_drvdata(pdev, priv); ++ ++ return 0; ++err_adap_fail: ++ of_node_put(adap_node); ++err_enable_fail: ++ /* nothing */ ++err_node_fail: ++ /* nothing */ ++err_prop_fail: ++ devm_kfree(&pdev->dev, priv); ++ return ret; ++} ++ ++static int __devexit i2c_dt_remove(struct platform_device *pdev) ++{ ++ return -EINVAL; /* not supporting removal yet */ ++} ++ ++static struct platform_driver i2c_dt_driver = { ++ .probe = i2c_dt_probe, ++ .remove = __devexit_p(i2c_dt_remove), ++ .driver = { ++ .name = "i2c-dt", ++ .owner = THIS_MODULE, ++ .of_match_table = of_i2c_dt_match, ++ }, ++}; ++ ++struct spi_priv { ++ struct spi_master *master; ++ phandle parent_handle; ++}; ++ ++static const struct of_device_id of_spi_dt_match[] = { ++ { .compatible = "spi-dt", }, ++ {}, ++}; ++ ++static int of_dev_node_match(struct device *dev, void *data) ++{ ++ return dev->of_node == data; ++} ++ ++/* must call put_device() when done with returned i2c_adapter device */ ++static struct spi_master *of_find_spi_master_by_node(struct device_node *node) ++{ ++ struct device *dev; ++ struct spi_master *master; ++ ++ dev = class_find_device(&spi_master_class, NULL, node, ++ of_dev_node_match); ++ if (!dev) ++ return NULL; ++ ++ master = container_of(dev, struct spi_master, dev); ++ ++ /* TODO: No checks what-so-ever... be careful. */ ++ return master; ++} ++ ++static int __devinit spi_dt_probe(struct platform_device *pdev) ++{ ++ struct spi_priv *priv = NULL; ++ int ret = -EINVAL; ++ struct device_node *master_node; ++ u32 val; ++ ++ if (pdev->dev.of_node == NULL) { ++ dev_err(&pdev->dev, "Only support OF case\n"); ++ return -ENOMEM; ++ } ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (priv == NULL) { ++ dev_err(&pdev->dev, "Failed to allocate priv\n"); ++ return -ENOMEM; ++ } ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "parent", &val); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to find parent property\n"); ++ goto err_prop_fail; ++ } ++ priv->parent_handle = val; ++ ++ master_node = of_find_node_by_phandle(priv->parent_handle); ++ if (master_node == NULL) { ++ dev_err(&pdev->dev, "Failed to find spi bus master node\n"); ++ ret = -EINVAL; ++ goto err_node_fail; ++ } ++ ++ ret = capebus_of_platform_device_enable(master_node); ++ if (ret != 0) { ++ dev_info(&pdev->dev, "SPI platform device failed to enable\n"); ++ goto err_enable_fail; ++ } ++ ++ priv->master = of_find_spi_master_by_node(master_node); ++ if (priv->master == NULL) { ++ dev_err(&pdev->dev, "Failed to find bus master node\n"); ++ ret = -EINVAL; ++ goto err_master_fail; ++ } ++ ++ of_register_node_spi_devices(priv->master, pdev->dev.of_node); ++ ++ of_node_put(master_node); ++ ++ dev_info(&pdev->dev, "Registered bone SPI OK.\n"); ++ ++ platform_set_drvdata(pdev, priv); ++ ++ return 0; ++err_master_fail: ++ of_node_put(master_node); ++err_enable_fail: ++ /* nothing */ ++err_node_fail: ++ /* nothing */ ++err_prop_fail: ++ devm_kfree(&pdev->dev, priv); ++ return ret; ++} ++ ++static int __devexit spi_dt_remove(struct platform_device *pdev) ++{ ++ return -EINVAL; /* not supporting removal yet */ ++} ++ ++static struct platform_driver spi_dt_driver = { ++ .probe = spi_dt_probe, ++ .remove = __devexit_p(spi_dt_remove), ++ .driver = { ++ .name = "spi-dt", ++ .owner = THIS_MODULE, ++ .of_match_table = of_spi_dt_match, ++ }, ++}; ++ ++/* ++ * ++ */ ++struct bone_capebus_pdev_driver { ++ struct platform_driver *driver; ++ unsigned int registered : 1; ++ /* more? */ ++}; ++ ++static struct bone_capebus_pdev_driver pdev_drivers[] = { ++#if defined(CONFIG_FB_DA8XX) || defined(CONFIG_FB_DA8XX_MODULE) ++ { ++ .driver = &da8xx_dt_driver, ++ }, ++#endif ++#if defined(CONFIG_MFD_TI_AM335X_TSCADC) || defined(CONFIG_MFD_TI_AM335X_TSCADC_MODULE) ++ { ++ .driver = &ti_tscadc_dt_driver, ++ }, ++#endif ++ { ++ .driver = &i2c_dt_driver, ++ }, ++ { ++ .driver = &spi_dt_driver, ++ }, ++ { ++ .driver = NULL, ++ } ++}; ++ ++int bone_capebus_register_pdev_adapters(struct bone_capebus_bus *bus) ++{ ++ struct bone_capebus_pdev_driver *drvp; ++ int err; ++ ++ /* first check if we do it twice */ ++ for (drvp = pdev_drivers; drvp->driver != NULL; drvp++) ++ if (drvp->registered) ++ return -EBUSY; ++ ++ for (drvp = pdev_drivers; drvp->driver != NULL; drvp++) { ++ ++ err = platform_driver_register(drvp->driver); ++ if (err != 0) ++ goto err_out; ++ ++ drvp->registered = 1; ++ ++ dev_info(bus->dev, "Registered %s " ++ "platform driver\n", drvp->driver->driver.name); ++ } ++ ++ return 0; ++ ++err_out: ++ dev_err(bus->dev, "Failed to register %s " ++ "platform driver\n", drvp->driver->driver.name); ++ ++ /* unregister */ ++ while (--drvp >= pdev_drivers) { ++ ++ if (!drvp->registered) ++ continue; ++ ++ platform_driver_unregister(drvp->driver); ++ } ++ ++ return err; ++} ++ ++void bone_capebus_unregister_pdev_adapters(struct bone_capebus_bus *bus) ++{ ++ struct bone_capebus_pdev_driver *drvp; ++ ++ /* unregister */ ++ drvp = &pdev_drivers[ARRAY_SIZE(pdev_drivers)]; ++ while (--drvp >= pdev_drivers) { ++ ++ if (drvp->driver == NULL) /* skip terminator */ ++ continue; ++ ++ if (!drvp->registered) ++ continue; ++ ++ platform_driver_unregister(drvp->driver); ++ ++ drvp->registered = 0; ++ } ++} +diff --git a/drivers/capebus/boards/capebus-bone.c b/drivers/capebus/boards/capebus-bone.c +new file mode 100644 +index 0000000..33a6bde +--- /dev/null ++++ b/drivers/capebus/boards/capebus-bone.c +@@ -0,0 +1,931 @@ ++/* ++ * TI Beaglebone capebus controller ++ * ++ * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com> ++ * Copyright (C) 2012 Texas Instruments Inc. ++ * ++ * 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 <linux/module.h> ++#include <linux/delay.h> ++#include <linux/i2c.h> ++#include <linux/err.h> ++#include <linux/interrupt.h> ++#include <linux/completion.h> ++#include <linux/platform_device.h> ++#include <linux/clk.h> ++#include <linux/io.h> ++#include <linux/of.h> ++#include <linux/of_i2c.h> ++#include <linux/of_device.h> ++#include <linux/slab.h> ++#include <linux/pm_runtime.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/err.h> ++#include <linux/ctype.h> ++ ++#include <linux/capebus.h> ++#include <linux/capebus/capebus-bone.h> ++ ++/* what to fill in to the cntrlboard field of the id */ ++#define BONE_CAPEBUS_CNTRLBOARD "beaglebone" ++ ++/* various EEPROM definition for the bone */ ++struct bone_capebus_eeprom_field { ++ const char *name; ++ int start; ++ int size; ++ unsigned int ascii : 1; ++ unsigned int strip_trailing_dots : 1; ++ const char *override; ++}; ++ ++static const struct bone_capebus_eeprom_field eeprom_fields[] = { ++ [BONE_CAPEBUS_HEADER] = { ++ .name = "header", ++ .start = 0, ++ .size = 4, ++ .ascii = 0, ++ .override = "\xaa\x55\x33\xee", /* AA 55 33 EE */ ++ }, ++ [BONE_CAPEBUS_EEPROM_REV] = { ++ .name = "eeprom-format-revision", ++ .start = 4, ++ .size = 2, ++ .ascii = 1, ++ .override = "A0", ++ }, ++ [BONE_CAPEBUS_BOARD_NAME] = { ++ .name = "board-name", ++ .start = 6, ++ .size = 32, ++ .ascii = 1, ++ .strip_trailing_dots = 1, ++ .override = "Override Board Name", ++ }, ++ [BONE_CAPEBUS_VERSION] = { ++ .name = "version", ++ .start = 38, ++ .size = 4, ++ .ascii = 1, ++ .override = "00A0", ++ }, ++ [BONE_CAPEBUS_MANUFACTURER] = { ++ .name = "manufacturer", ++ .start = 42, ++ .size = 16, ++ .ascii = 1, ++ .strip_trailing_dots = 1, ++ .override = "Override Manuf", ++ }, ++ [BONE_CAPEBUS_PART_NUMBER] = { ++ .name = "part-number", ++ .start = 58, ++ .size = 16, ++ .ascii = 1, ++ .override = "Override Part#", ++ }, ++ [BONE_CAPEBUS_NUMBER_OF_PINS] = { ++ .name = "number-of-pins", ++ .start = 74, ++ .size = 2, ++ .ascii = 0, ++ .override = NULL, ++ }, ++ [BONE_CAPEBUS_SERIAL_NUMBER] = { ++ .name = "serial-number", ++ .start = 76, ++ .size = 12, ++ .ascii = 1, ++ .override = "0000000000", ++ }, ++ [BONE_CAPEBUS_PIN_USAGE] = { ++ .name = "pin-usage", ++ .start = 88, ++ .size = 140, ++ .ascii = 0, ++ .override = NULL, ++ }, ++ [BONE_CAPEBUS_VDD_3V3EXP] = { ++ .name = "vdd-3v3exp", ++ .start = 228, ++ .size = 2, ++ .ascii = 0, ++ .override = NULL, ++ }, ++ [BONE_CAPEBUS_VDD_5V] = { ++ .name = "vdd-5v", ++ .start = 230, ++ .size = 2, ++ .ascii = 0, ++ .override = NULL, ++ }, ++ [BONE_CAPEBUS_SYS_5V] = { ++ .name = "sys-5v", ++ .start = 232, ++ .size = 2, ++ .ascii = 0, ++ .override = NULL, ++ }, ++ [BONE_CAPEBUS_DC_SUPPLIED] = { ++ .name = "dc-supplied", ++ .start = 234, ++ .size = 2, ++ .ascii = 0, ++ .override = NULL, ++ }, ++}; ++ ++char *bone_capebus_id_get_field(const struct cape_device_id *id, ++ int field, char *buf, int bufsz) ++{ ++ const struct bone_capebus_eeprom_field *ee_field; ++ int len; ++ ++ /* make sure the ID is valid for the bone */ ++ if (bone_capebus_match_cntrlboard(id) != 0) ++ return NULL; ++ ++ if ((unsigned int)field >= ARRAY_SIZE(eeprom_fields)) ++ return NULL; ++ ++ ee_field = &eeprom_fields[field]; ++ ++ /* enough space? */ ++ if (bufsz < ee_field->size + ee_field->ascii) ++ return NULL; ++ ++ memcpy(buf, (char *)id->data + ee_field->start, ee_field->size); ++ ++ /* terminate ascii field */ ++ if (ee_field->ascii) ++ buf[ee_field->size] = '\0';; ++ ++ if (ee_field->strip_trailing_dots) { ++ len = strlen(buf); ++ while (len > 1 && buf[len - 1] == '.') ++ buf[--len] = '\0'; ++ } ++ ++ return buf; ++} ++EXPORT_SYMBOL(bone_capebus_id_get_field); ++ ++int bone_capebus_match_cntrlboard(const struct cape_device_id *id) ++{ ++ if (strcmp(id->cntrlboard, BONE_CAPEBUS_CNTRLBOARD) != 0) ++ return -ENODEV; ++ return 0; ++} ++EXPORT_SYMBOL(bone_capebus_match_cntrlboard); ++ ++int bone_capebus_match_board(const struct cape_device_id *id, ++ const char **board_names) ++{ ++ char rname[33]; ++ const char *s; ++ int ret; ++ int i; ++ ++ /* be safe; check for matching cntrlboard */ ++ ret = bone_capebus_match_cntrlboard(id); ++ if (ret != 0) ++ return ret; ++ ++ s = bone_capebus_id_get_field(id, BONE_CAPEBUS_BOARD_NAME, ++ rname, sizeof(rname)); ++ if (s == NULL) ++ return -EINVAL; ++ ++ i = 0; ++ while (*board_names) { ++ if (strcmp(rname, *board_names) == 0) ++ return i; ++ board_names++; ++ } ++ ++ return -1; ++} ++EXPORT_SYMBOL(bone_capebus_match_board); ++ ++#ifdef CONFIG_OF ++static const struct of_device_id bone_capebus_of_match[] = { ++ { ++ .compatible = "bone-capebus", ++ }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, bone_capebus_of_match); ++ ++static const struct of_device_id slot_override_of_match[] = { ++ { ++ .compatible = "bone-capebus-slot-override", ++ }, ++ { }, ++}; ++ ++#endif ++ ++const struct cape_device_id *bone_capebus_get_dev_id(struct cape_slot *slot) ++{ ++ struct cape_bus *bus = slot->bus; ++ struct bone_capebus_slot *bone_slot = to_bone_capebus_slot(slot); ++ struct i2c_client *client = bone_slot->client; ++ struct cape_device_id *id; ++ const u8 *p; ++ int r; ++ char board_name[32+1]; ++ char version[4+1]; ++ char manufacturer[16+1]; ++ char part_number[16+1]; ++ ++ id = &bone_slot->id; ++ ++ /* need to read EEPROM? */ ++ if (!bone_slot->eeprom_probed) { ++ ++ bone_slot->eeprom_probed = 1; ++ ++ if (!bone_slot->eeprom_override) { ++ r = i2c_memory_read(bone_slot->client, ++ bone_slot->eeprom_signature, 0, ++ sizeof(bone_slot->eeprom_signature)); ++ if (r != sizeof(bone_slot->eeprom_signature)) { ++ dev_err(&bus->dev, ++ "bone: Failed to read EEPROM at " ++ "slot %d (addr 0x%02x)\n", ++ slot->slotno, client->addr & 0x7f); ++ bone_slot->eeprom_failed = 1; ++ return NULL; ++ } ++ } else ++ dev_info(&bus->dev, ++ "bone: Using override eeprom data at slot %d\n", ++ slot->slotno); ++ ++ p = bone_slot->eeprom_signature; ++ if (BONE_CAPEBUS_MAKE_HEADER(p) != BONE_CAPEBUS_HEADER_VALID) { ++ dev_err(&bus->dev, "bone: Invalid EEPROM signature " ++ "'%08x' at slot %d (addr 0x%02x)\n", ++ BONE_CAPEBUS_MAKE_HEADER(p), ++ slot->slotno, client->addr & 0x7f); ++ bone_slot->eeprom_failed = 1; ++ return NULL; ++ } ++ ++ bone_slot->id.cntrlboard = BONE_CAPEBUS_CNTRLBOARD; ++ bone_slot->id.len = sizeof(bone_slot->eeprom_signature); ++ bone_slot->id.data = bone_slot->eeprom_signature; ++ ++ bone_capebus_id_get_field(id, BONE_CAPEBUS_BOARD_NAME, ++ board_name, sizeof(board_name)); ++ bone_capebus_id_get_field(id, BONE_CAPEBUS_VERSION, ++ version, sizeof(version)); ++ bone_capebus_id_get_field(id, BONE_CAPEBUS_MANUFACTURER, ++ manufacturer, sizeof(manufacturer)); ++ bone_capebus_id_get_field(id, BONE_CAPEBUS_PART_NUMBER, ++ part_number, sizeof(part_number)); ++ ++ /* board_name,version,manufacturer,part_number */ ++ snprintf(bone_slot->text_id, sizeof(bone_slot->text_id) - 1, ++ "%s,%s,%s,%s", board_name, version, ++ manufacturer, part_number); ++ ++ /* terminate always */ ++ bone_slot->text_id[sizeof(bone_slot->text_id) - 1] = '\0'; ++ ++ } ++ ++ /* slot has failed and we don't support hotpluging */ ++ if (bone_slot->eeprom_failed) ++ return NULL; ++ ++ return id; ++} ++ ++const char *bone_capebus_get_text_dev_id(struct cape_slot *slot) ++{ ++ struct bone_capebus_slot *bone_slot = to_bone_capebus_slot(slot); ++ ++ if (bone_slot->eeprom_failed || !bone_slot->eeprom_probed) ++ return NULL; ++ ++ return bone_slot->text_id; ++} ++ ++struct bonedev_ee_attribute { ++ struct device_attribute devattr; ++ unsigned int field; ++}; ++#define to_bonedev_ee_attribute(x) \ ++ container_of((x), struct bonedev_ee_attribute, devattr) ++ ++static ssize_t bonedev_ee_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct bonedev_ee_attribute *ee_attr = to_bonedev_ee_attribute(attr); ++ struct cape_dev *cdev = to_cape_dev(dev); ++ const struct cape_device_id *id = cdev->id; ++ const struct bone_capebus_eeprom_field *ee_field; ++ int i, len; ++ char *p, *s; ++ u16 val; ++ ++ if (id == NULL) ++ return -EINVAL; ++ ++ /* add newline for ascii fields */ ++ ee_field = &eeprom_fields[ee_attr->field]; ++ ++ len = ee_field->size + ee_field->ascii; ++ p = kmalloc(len, GFP_KERNEL); ++ if (p == NULL) ++ return -ENOMEM; ++ ++ s = bone_capebus_id_get_field(id, ee_attr->field, p, len); ++ if (s == NULL) ++ return -EINVAL; ++ ++ /* add newline for ascii fields and return */ ++ if (ee_field->ascii) { ++ len = sprintf(buf, "%s\n", s); ++ goto out; ++ } ++ ++ /* case by case handling */ ++ switch (ee_attr->field) { ++ case BONE_CAPEBUS_HEADER: ++ len = sprintf(buf, "%02x %02x %02x %02x\n", ++ s[0], s[1], s[2], s[3]); ++ break; ++ ++ /* 2 bytes */ ++ case BONE_CAPEBUS_NUMBER_OF_PINS: ++ case BONE_CAPEBUS_VDD_3V3EXP: ++ case BONE_CAPEBUS_VDD_5V: ++ case BONE_CAPEBUS_SYS_5V: ++ case BONE_CAPEBUS_DC_SUPPLIED: ++ /* the bone is LE */ ++ val = s[0] & (s[1] << 8); ++ len = sprintf(buf, "%u\n", (unsigned int)val & 0xffff); ++ break; ++ ++ case BONE_CAPEBUS_PIN_USAGE: ++ ++ len = 0; ++ for (i = 0; i < ee_field->size / 2; i++) { ++ /* the bone is LE */ ++ val = s[0] & (s[1] << 8); ++ sprintf(buf, "%04x\n", val); ++ buf += 5; ++ len += 5; ++ s += 2; ++ } ++ ++ break; ++ ++ default: ++ *buf = '\0'; ++ len = 0; ++ break; ++ } ++ ++out: ++ kfree(p); ++ ++ return len; ++} ++ ++#define BONEDEV_EE_ATTR(_name, _field) \ ++ { \ ++ .devattr = __ATTR(_name, 0440, bonedev_ee_show, NULL), \ ++ .field = BONE_CAPEBUS_##_field , \ ++ } ++ ++struct bonedev_ee_attribute ee_attrs[] = { ++ BONEDEV_EE_ATTR(header, HEADER), ++ BONEDEV_EE_ATTR(eeprom-format-revision, EEPROM_REV), ++ BONEDEV_EE_ATTR(board-name, BOARD_NAME), ++ BONEDEV_EE_ATTR(version, VERSION), ++ BONEDEV_EE_ATTR(manufacturer, MANUFACTURER), ++ BONEDEV_EE_ATTR(part-number, PART_NUMBER), ++ BONEDEV_EE_ATTR(number-of-pins, NUMBER_OF_PINS), ++ BONEDEV_EE_ATTR(serial-number, SERIAL_NUMBER), ++ BONEDEV_EE_ATTR(pin-usage, PIN_USAGE), ++ BONEDEV_EE_ATTR(vdd-3v3exp, VDD_3V3EXP), ++ BONEDEV_EE_ATTR(vdd-5v, VDD_5V), ++ BONEDEV_EE_ATTR(sys-5v, SYS_5V), ++ BONEDEV_EE_ATTR(dc-supplied, DC_SUPPLIED), ++}; ++ ++static struct attribute *ee_attrs_flat[] = { ++ &ee_attrs[BONE_CAPEBUS_HEADER ].devattr.attr, ++ &ee_attrs[BONE_CAPEBUS_EEPROM_REV ].devattr.attr, ++ &ee_attrs[BONE_CAPEBUS_BOARD_NAME ].devattr.attr, ++ &ee_attrs[BONE_CAPEBUS_VERSION ].devattr.attr, ++ &ee_attrs[BONE_CAPEBUS_MANUFACTURER ].devattr.attr, ++ &ee_attrs[BONE_CAPEBUS_PART_NUMBER ].devattr.attr, ++ &ee_attrs[BONE_CAPEBUS_NUMBER_OF_PINS ].devattr.attr, ++ &ee_attrs[BONE_CAPEBUS_SERIAL_NUMBER ].devattr.attr, ++ &ee_attrs[BONE_CAPEBUS_PIN_USAGE ].devattr.attr, ++ &ee_attrs[BONE_CAPEBUS_VDD_3V3EXP ].devattr.attr, ++ &ee_attrs[BONE_CAPEBUS_VDD_5V ].devattr.attr, ++ &ee_attrs[BONE_CAPEBUS_SYS_5V ].devattr.attr, ++ &ee_attrs[BONE_CAPEBUS_DC_SUPPLIED ].devattr.attr, ++ NULL, ++}; ++ ++static const struct attribute_group bone_ee_attrgroup = { ++ .name = "ee-fields", ++ .is_visible = NULL, ++ .attrs = ee_attrs_flat, ++}; ++ ++static int bone_capebus_sysfs_register(struct cape_dev *dev) ++{ ++ return sysfs_create_group(&dev->dev.kobj, &bone_ee_attrgroup); ++} ++ ++static void bone_capebus_sysfs_unregister(struct cape_dev *dev) ++{ ++ sysfs_remove_group(&dev->dev.kobj, &bone_ee_attrgroup); ++} ++ ++static int bone_capebus_dev_probed(struct cape_dev *dev) ++{ ++ return 0; ++} ++ ++static void bone_capebus_dev_removed(struct cape_dev *dev) ++{ ++ bone_capebus_sysfs_unregister(dev); ++} ++ ++static int bone_capebus_dev_registered(struct cape_dev *dev) ++{ ++ int ret; ++ ++ ret = bone_capebus_sysfs_register(dev); ++ if (ret != 0) { ++ dev_err(&dev->dev, "bone_capebus sysfs registration failed\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static struct cape_bus_ops bone_capebus_ops = { ++ .get_dev_id = bone_capebus_get_dev_id, ++ .get_text_dev_id = bone_capebus_get_text_dev_id, ++ .dev_probed = bone_capebus_dev_probed, ++ .dev_removed = bone_capebus_dev_removed, ++ .dev_registered = bone_capebus_dev_registered, ++}; ++ ++static ssize_t slots_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct bone_capebus_bus *bus = platform_get_drvdata(pdev); ++ struct bone_capebus_slot *slot; ++ ssize_t len, sz; ++ int i; ++ ++ sz = 0; ++ ++ for (i = 0; i < bus->slots_nr; i++) { ++ slot = &bus->slots[i]; ++ ++ len = sprintf(buf, "%02x:%c%c%c%c %s\n", ++ (int)slot->eeprom_addr & 0x7f, ++ slot->eeprom_probed ? 'P' : '-', ++ slot->eeprom_failed ? 'F' : '-', ++ slot->eeprom_override ? 'O' : '-', ++ (slot->cape_slot.dev && slot->cape_slot.dev->added) ? 'A' : '-', ++ slot->text_id); ++ ++ buf += len; ++ sz += len; ++ } ++ return sz; ++} ++ ++static ssize_t slots_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct bone_capebus_bus *bus = platform_get_drvdata(pdev); ++ int slotno, err, i, len; ++ char *s, *board_name, *version, *p; ++ const struct bone_capebus_eeprom_field *ee_field, *eebrd, *eevrs; ++ struct bone_capebus_slot *slot; ++ ++ eebrd = &eeprom_fields[BONE_CAPEBUS_BOARD_NAME]; ++ eevrs = &eeprom_fields[BONE_CAPEBUS_VERSION]; ++ ++ slotno = simple_strtoul(buf, &s, 10); ++ if (slotno < 0 || slotno >= bus->slots_nr) ++ return -EINVAL; ++ slot = &bus->slots[slotno]; ++ if (slot->eeprom_override || (slot->cape_slot.dev && slot->cape_slot.dev->added)) ++ return -EINVAL; ++ ++ board_name = kzalloc(eebrd->size + 1 + eevrs->size + 1, GFP_KERNEL); ++ if (board_name == NULL) ++ return -ENOMEM; ++ version = board_name + eebrd->size + 1; ++ ++ s = strchr(s, ':'); ++ if (s == NULL) { ++ kfree(board_name); ++ return -EINVAL; ++ } ++ s++; ++ p = strchr(s, ':'); ++ if (p == NULL) { ++ len = strlen(s); ++ strncpy(board_name, s, eebrd->size); ++ strcpy(version, "00A0"); ++ } else { ++ len = p - s; ++ if (len > eebrd->size) ++ len = p - s; ++ memcpy(board_name, s, len); ++ board_name[len] = '\0'; ++ strncpy(version, p + 1, eevrs->size); ++ } ++ board_name[eebrd->size] = '\0'; ++ version[eevrs->size] = '\0'; ++ ++ /* strip trailing spaces, dots & newlines */ ++ s = board_name + strlen(board_name); ++ while (s > board_name && ++ (isspace(s[-1]) || s[-1] == '\n' || s[-1] == '.')) ++ *--s = '\0'; ++ ++ printk(KERN_INFO "Override for slot #%d, board-name '%s', version '%s'\n", ++ slotno, board_name, version); ++ ++ slot->eeprom_override = 1; ++ slot->eeprom_failed = 0; ++ slot->eeprom_probed = 0; ++ ++ /* zero out signature */ ++ memset(slot->eeprom_signature, 0, ++ sizeof(slot->eeprom_signature)); ++ ++ /* create an eeprom field */ ++ for (i = 0; i < ARRAY_SIZE(eeprom_fields); i++) { ++ ++ ee_field = &eeprom_fields[i]; ++ ++ /* point to the entry */ ++ p = slot->eeprom_signature + ee_field->start; ++ ++ /* if no such property, assign default */ ++ if (i != BONE_CAPEBUS_BOARD_NAME) { ++ ++ if (ee_field->override) ++ memcpy(p, ee_field->override, ++ ee_field->size); ++ else ++ memset(p, 0, ee_field->size); ++ ++ continue; ++ } ++ ++ /* copy it to the eeprom signature buf */ ++ len = strlen(board_name); ++ if (len > ee_field->size) ++ len = ee_field->size; ++ ++ /* copy and zero out rest */ ++ memcpy(p, board_name, len); ++ if (len < ee_field->size) ++ memset(p + len, 0, ee_field->size - len); ++ } ++ ++ printk(KERN_INFO "calling cape_bus_scan_one_slot\n"); ++ err = cape_bus_scan_one_slot(&bus->cape_bus, &slot->cape_slot); ++ ++ printk(KERN_INFO "cape_bus_scan_one_slot returned %d\n", err); ++ ++ /* failed to scan... */ ++ if (err != 0) ++ slot->eeprom_override = 0; ++ ++ kfree(board_name); ++ ++ return strlen(buf); ++} ++ ++static DEVICE_ATTR(slots, 0644, slots_show, slots_store); ++ ++static int bone_capebus_bus_sysfs_register(struct bone_capebus_bus *bus) ++{ ++ return device_create_file(bus->dev, &dev_attr_slots); ++} ++ ++static void bone_capebus_bus_sysfs_unregister(struct bone_capebus_bus *bus) ++{ ++ device_remove_file(bus->dev, &dev_attr_slots); ++} ++ ++static int __devinit ++bone_capebus_probe(struct platform_device *pdev) ++{ ++ struct bone_capebus_bus *bus; ++ struct device_node *pnode = pdev->dev.of_node; ++ const struct of_device_id *cntrlboard_match; ++ const struct of_device_id *dev_match; ++ struct bone_capebus_slot *slot; ++ const struct bone_capebus_eeprom_field *ee_field; ++ struct property *prop; ++ int length; ++ int r; ++ struct device_node *node; ++ struct i2c_client *client; ++ phandle handle; ++ u32 *slot_handles = NULL; ++ u32 val; ++ const char *str; ++ u8 *p; ++ int i, len; ++ ++ /* we don't use platform_data */ ++ ++ bus = devm_kzalloc(&pdev->dev, ++ sizeof(struct bone_capebus_bus), GFP_KERNEL); ++ if (!bus) { ++ dev_err(&pdev->dev, "Failed to allocate device structure\n"); ++ return -ENOMEM; ++ } ++ ++ /* register the cape bus */ ++ r = cape_bus_register(&bus->cape_bus, "bone", 0, &pdev->dev, ++ &bone_capebus_ops); ++ if (r != 0) { ++ dev_err(&pdev->dev, "Failed to register the cape device\n"); ++ return r; ++ } ++ ++ cntrlboard_match = of_match_device(of_match_ptr(bone_capebus_of_match), ++ &pdev->dev); ++ if (!cntrlboard_match) { ++ dev_err(&pdev->dev, "Failed to configure bone capebus\n"); ++ return -ENODEV; ++ } ++ bus->dev = &pdev->dev; ++ ++ prop = of_find_property(pnode, "slots", &length); ++ if (prop == NULL) { ++ dev_err(&pdev->dev, "Unable to find required " ++ "property 'slots'\n"); ++ return -EINVAL; ++ } ++ bus->slots_nr = length / sizeof(u32); ++ bus->slots = devm_kzalloc(&pdev->dev, ++ sizeof(bus->slots[0]) * bus->slots_nr, GFP_KERNEL); ++ if (!bus->slots) { ++ dev_err(&pdev->dev, "Failed to allocate %d slot areas\n", ++ bus->slots_nr); ++ return -ENOMEM; ++ } ++ slot_handles = devm_kzalloc(&pdev->dev, length, GFP_KERNEL); ++ if (!slot_handles) { ++ dev_err(&pdev->dev, "Failed to allocate %d slot areas\n", ++ bus->slots_nr); ++ return -ENOMEM; ++ } ++ r = of_property_read_u32_array(pnode, "slots", ++ slot_handles, bus->slots_nr); ++ if (r < 0) { ++ dev_err(&pdev->dev, "Failed to read %d slot handles\n", ++ bus->slots_nr); ++ return r; ++ } ++ ++ /* now we iterate over any overrides */ ++ for_each_child_of_node(pnode, node) { ++ ++ dev_match = of_match_node(slot_override_of_match, node); ++ if (!dev_match) ++ continue; ++ ++ /* no reg property */ ++ if (of_property_read_u32(node, "slot", &val) != 0) { ++ dev_warn(&pdev->dev, "override: Failed to read " ++ "slot property\n"); ++ continue; ++ } ++ ++ if (val >= bus->slots_nr) { ++ dev_warn(&pdev->dev, "override: invalid slot #%u\n", ++ val); ++ continue; ++ } ++ ++ slot = &bus->slots[val]; ++ ++ if (slot->eeprom_override) { ++ dev_warn(&pdev->dev, "override: slot #%u is already " ++ "overriden\n", val); ++ continue; ++ } ++ ++ slot->eeprom_override = 1; ++ ++ /* zero out signature */ ++ memset(slot->eeprom_signature, 0, ++ sizeof(slot->eeprom_signature)); ++ ++ /* for any matching field assign them */ ++ for (i = 0; i < ARRAY_SIZE(eeprom_fields); i++) { ++ ++ ee_field = &eeprom_fields[i]; ++ ++ /* point to the entry */ ++ p = slot->eeprom_signature + ee_field->start; ++ ++ /* if no such property, assign default */ ++ if (of_property_read_string(node, ee_field->name, ++ &str) != 0) { ++ ++ if (ee_field->override) ++ memcpy(p, ee_field->override, ++ ee_field->size); ++ else ++ memset(p, 0, ee_field->size); ++ ++ continue; ++ } ++ ++ /* copy it to the eeprom signature buf */ ++ len = strlen(str); ++ if (len > ee_field->size) ++ len = ee_field->size; ++ ++ /* copy and zero out rest */ ++ memcpy(p, str, len); ++ if (len < ee_field->size) ++ memset(p + len, 0, ee_field->size - len); ++ } ++ } ++ ++ platform_set_drvdata(pdev, bus); ++ ++ /* now find the i2c clients */ ++ for (i = 0; i < bus->slots_nr; i++) { ++ ++ slot = &bus->slots[i]; ++ ++ handle = slot_handles[i]; ++ node = of_find_node_by_phandle(handle); ++ if (node == NULL) { ++ dev_warn(&pdev->dev, "Failed to find node with phandle " ++ "0x%x (#%d)\n", handle, i); ++ continue; ++ } ++ dev_dbg(&pdev->dev, "Found device node for phandle " ++ "0x%x (#%d)\n", handle, i); ++ ++ client = of_find_i2c_device_by_node(node); ++ if (client == NULL) { ++ dev_warn(&pdev->dev, "Invalid I2C client node with " ++ "phandle 0x%x (#%d)\n", handle, i); ++ continue; ++ } ++ ++ slot->client = i2c_use_client(client); ++ /* no use for this anymore */ ++ of_node_put(node); ++ ++ /* save handle */ ++ client = slot->client; /* get again */ ++ slot->eeprom_addr = client->addr; ++ dev_dbg(&pdev->dev, "Found i2c_client at #%d " ++ "(address = 0x%02x)\n", ++ i, slot->eeprom_addr); ++ ++ r = cape_bus_register_slot(&bus->cape_bus, &slot->cape_slot, i); ++ if (r != 0) { ++ dev_err(&pdev->dev, "Failed to register slot #%d\n", i); ++ continue; ++ } ++ ++ dev_info(&pdev->dev, "Registered slot #%d OK\n", i); ++ } ++ ++ /* we don't need the handles anymore */ ++ devm_kfree(&pdev->dev, slot_handles); ++ slot_handles = NULL; ++ ++ r = bone_capebus_register_pdev_adapters(bus); ++ if (r != 0) { ++ dev_err(&pdev->dev, "Failed to register the pdev adapters\n"); ++ goto err_no_pdevs; ++ } ++ ++ pm_runtime_enable(bus->dev); ++ r = pm_runtime_get_sync(bus->dev); ++ if (IS_ERR_VALUE(r)) { ++ dev_err(&pdev->dev, "Failed to pm_runtime_get_sync()\n"); ++ goto err_exit; ++ } ++ ++ pm_runtime_put(bus->dev); ++ ++ bone_capebus_bus_sysfs_register(bus); ++ ++ dev_info(&pdev->dev, "initialized OK.\n"); ++ ++ return 0; ++ ++err_exit: ++ bone_capebus_unregister_pdev_adapters(bus); ++err_no_pdevs: ++ platform_set_drvdata(pdev, NULL); ++ ++ return r; ++} ++ ++static int __devexit bone_capebus_remove(struct platform_device *pdev) ++{ ++ struct bone_capebus_bus *bus = platform_get_drvdata(pdev); ++ int ret; ++ ++ bone_capebus_bus_sysfs_unregister(bus); ++ bone_capebus_unregister_pdev_adapters(bus); ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ ret = pm_runtime_get_sync(&pdev->dev); ++ if (IS_ERR_VALUE(ret)) ++ return ret; ++ ++ pm_runtime_put(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++#ifdef CONFIG_PM_RUNTIME ++static int bone_capebus_runtime_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct bone_capebus_bus *_dev = platform_get_drvdata(pdev); ++ ++ (void)_dev; ++ return 0; ++} ++ ++static int bone_capebus_runtime_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct bone_capebus_bus *_dev = platform_get_drvdata(pdev); ++ ++ (void)_dev; ++ return 0; ++} ++#endif /* CONFIG_PM_RUNTIME */ ++ ++static struct dev_pm_ops bone_capebus_pm_ops = { ++ SET_RUNTIME_PM_OPS(bone_capebus_runtime_suspend, ++ bone_capebus_runtime_resume, NULL) ++}; ++#define BONE_CAPEBUS_PM_OPS (&bone_capebus_pm_ops) ++#else ++#define BONE_CAPEBUS_PM_OPS NULL ++#endif /* CONFIG_PM */ ++ ++static struct platform_driver bone_capebus_driver = { ++ .probe = bone_capebus_probe, ++ .remove = __devexit_p(bone_capebus_remove), ++ .driver = { ++ .name = "bone-capebus", ++ .owner = THIS_MODULE, ++ .pm = BONE_CAPEBUS_PM_OPS, ++ .of_match_table = of_match_ptr(bone_capebus_of_match), ++ }, ++}; ++ ++module_platform_driver(bone_capebus_driver); ++ ++MODULE_AUTHOR("Pantelis Antoniou"); ++MODULE_DESCRIPTION("Beaglebone cape bus controller"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:capebus_bone"); +diff --git a/include/linux/capebus/capebus-bone.h b/include/linux/capebus/capebus-bone.h +new file mode 100644 +index 0000000..e394304 +--- /dev/null ++++ b/include/linux/capebus/capebus-bone.h +@@ -0,0 +1,120 @@ ++/* ++ * capebus-bone.h ++ * ++ * Cape bus defines and function prototypes for the beaglebone ++ * ++ * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com> ++ * Copyright (C) 2012 Texas Instruments Inc. ++ * ++ * 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_CAPEBUS_BONE_H ++#define LINUX_CAPEBUS_BONE_H ++ ++#include <linux/list.h> ++#include <linux/capebus.h> ++ ++struct bone_capebus_slot { ++ struct cape_slot cape_slot; ++ u32 slot_handle; ++ int eeprom_addr; ++ struct i2c_client *client; ++ unsigned int eeprom_probed : 1; ++ unsigned int eeprom_failed : 1; ++ unsigned int eeprom_override : 1; ++ struct cape_device_id id; ++ char text_id[256]; ++ char eeprom_signature[256]; ++}; ++ ++#define to_bone_capebus_slot(n) \ ++ container_of(n, struct bone_capebus_slot, cape_slot) ++ ++struct bone_capebus_bus { ++ struct cape_bus cape_bus; ++ struct device *dev; /* pdev->dev */ ++ int slots_nr; ++ struct bone_capebus_slot *slots; ++}; ++ ++#define to_bone_capebus_bus(n) \ ++ container_of(n, struct bone_capebus_bus, cape_bus) ++ ++#define BONE_CAPEBUS_HEADER 0 ++#define BONE_CAPEBUS_EEPROM_REV 1 ++#define BONE_CAPEBUS_BOARD_NAME 2 ++#define BONE_CAPEBUS_VERSION 3 ++#define BONE_CAPEBUS_MANUFACTURER 4 ++#define BONE_CAPEBUS_PART_NUMBER 5 ++#define BONE_CAPEBUS_NUMBER_OF_PINS 6 ++#define BONE_CAPEBUS_SERIAL_NUMBER 7 ++#define BONE_CAPEBUS_PIN_USAGE 8 ++#define BONE_CAPEBUS_VDD_3V3EXP 9 ++#define BONE_CAPEBUS_VDD_5V 10 ++#define BONE_CAPEBUS_SYS_5V 11 ++#define BONE_CAPEBUS_DC_SUPPLIED 12 ++#define BONE_CAPEBUS_FIELDS_NR 13 ++ ++#define BONE_CAPEBUS_MAKE_HEADER(p) \ ++ ({ \ ++ const u8 *_p = (p); \ ++ (((u32)_p[0] << 24) | ((u32)_p[1] << 16) | \ ++ ((u32)_p[2] << 8) | (u32)_p[3] ); \ ++ }) ++ ++#define BONE_CAPEBUS_HEADER_VALID 0xaa5533ee ++ ++char *bone_capebus_id_get_field(const struct cape_device_id *id, ++ int field, char *buf, int bufsz); ++ ++int bone_capebus_match_cntrlboard(const struct cape_device_id *id); ++ ++int bone_capebus_match_board(const struct cape_device_id *id, ++ const char **board_names); ++ ++/* in pdevs */ ++int bone_capebus_register_pdev_adapters(struct bone_capebus_bus *bus); ++void bone_capebus_unregister_pdev_adapters(struct bone_capebus_bus *bus); ++ ++/* generic cape support */ ++ ++struct bone_capebus_generic_device_data { ++ const char *name; ++ const struct of_device_id *of_match; ++ unsigned int units; ++}; ++ ++struct bone_capebus_generic_device_entry { ++ struct list_head node; ++ const struct bone_capebus_generic_device_data *data; ++ struct platform_device *pdev; ++}; ++ ++struct bone_capebus_generic_info { ++ struct cape_dev *dev; ++ struct list_head pdev_list; ++}; ++ ++int bone_capebus_probe_prolog(struct cape_dev *dev, ++ const struct cape_device_id *id); ++ ++struct bone_capebus_generic_info * ++bone_capebus_probe_generic(struct cape_dev *dev, ++ const struct cape_device_id *id); ++ ++void bone_capebus_remove_generic( ++ struct bone_capebus_generic_info *info); ++ ++#endif diff --git a/patches/linux-3.7-rc6/0135-capebus-Beaglebone-generic-board.patch b/patches/linux-3.7-rc6/0135-capebus-Beaglebone-generic-board.patch new file mode 100644 index 0000000..a122522 --- /dev/null +++ b/patches/linux-3.7-rc6/0135-capebus-Beaglebone-generic-board.patch @@ -0,0 +1,135 @@ +From 48eaefd05e5487625d5b58c959daf785af664b95 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Tue, 30 Oct 2012 21:09:49 +0200 +Subject: [PATCH] capebus: Beaglebone generic board + +--- + drivers/capebus/capes/Kconfig | 6 ++ + drivers/capebus/capes/Makefile | 1 + + drivers/capebus/capes/bone-generic-cape.c | 96 +++++++++++++++++++++++++++++ + 3 files changed, 103 insertions(+) + create mode 100644 drivers/capebus/capes/Kconfig + create mode 100644 drivers/capebus/capes/Makefile + create mode 100644 drivers/capebus/capes/bone-generic-cape.c + +diff --git a/drivers/capebus/capes/Kconfig b/drivers/capebus/capes/Kconfig +new file mode 100644 +index 0000000..bfe54a6 +--- /dev/null ++++ b/drivers/capebus/capes/Kconfig +@@ -0,0 +1,6 @@ ++config CAPEBUS_BONE_GENERIC ++ tristate "Beaglebone Generic cape driver" ++ depends on CAPEBUS_BONE_CONTROLLER ++ default n ++ help ++ "Select this to enable a generic cape driver; LCD/DVI capes etc" +diff --git a/drivers/capebus/capes/Makefile b/drivers/capebus/capes/Makefile +new file mode 100644 +index 0000000..83da381 +--- /dev/null ++++ b/drivers/capebus/capes/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_CAPEBUS_BONE_GENERIC) += bone-generic-cape.o +diff --git a/drivers/capebus/capes/bone-generic-cape.c b/drivers/capebus/capes/bone-generic-cape.c +new file mode 100644 +index 0000000..70be50a +--- /dev/null ++++ b/drivers/capebus/capes/bone-generic-cape.c +@@ -0,0 +1,96 @@ ++/* ++ * Generic cape support ++ * ++ * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com> ++ * Copyright (C) 2012 Texas Instruments Inc. ++ * ++ * 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 <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/string.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/bitops.h> ++#include <linux/err.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_gpio.h> ++#include <linux/pinctrl/pinctrl.h> ++#include <linux/pinctrl/pinmux.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/atomic.h> ++#include <linux/clk.h> ++#include <asm/barrier.h> ++#include <plat/clock.h> ++#include <plat/omap_device.h> ++#include <linux/clkdev.h> ++#include <linux/input/ti_am335x_tsc.h> ++#include <linux/platform_data/ti_am335x_adc.h> ++#include <linux/mfd/ti_am335x_tscadc.h> ++ ++#include <linux/capebus/capebus-bone.h> ++ ++/* fwd decl. */ ++extern struct cape_driver bonegeneric_driver; ++ ++static const struct of_device_id bonegeneric_of_match[] = { ++ { ++ .compatible = "bone-generic-cape", ++ }, { }, ++}; ++MODULE_DEVICE_TABLE(of, bonegeneric_of_match); ++ ++static int bonegeneric_probe(struct cape_dev *dev, ++ const struct cape_device_id *id) ++{ ++ struct bone_capebus_generic_info *ginfo; ++ int err; ++ ++ err = bone_capebus_probe_prolog(dev, id); ++ if (err != 0) ++ return err; ++ ++ ginfo = bone_capebus_probe_generic(dev, id); ++ if (IS_ERR_OR_NULL(ginfo)) ++ return IS_ERR(ginfo) ? PTR_ERR(ginfo) : -ENODEV; ++ dev->drv_priv = ginfo; ++ return 0; ++} ++ ++static void bonegeneric_remove(struct cape_dev *dev) ++{ ++ bone_capebus_remove_generic(dev->drv_priv); ++} ++ ++struct cape_driver bonegeneric_driver = { ++ .driver = { ++ .name = "bonegeneric", ++ .owner = THIS_MODULE, ++ .of_match_table = bonegeneric_of_match, ++ }, ++ .probe = bonegeneric_probe, ++ .remove = bonegeneric_remove, ++}; ++ ++module_capebus_driver(bonegeneric_driver); ++ ++MODULE_AUTHOR("Pantelis Antoniou"); ++MODULE_DESCRIPTION("Beaglebone generic cape"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:bone-generic-cape"); diff --git a/patches/linux-3.7-rc6/0136-capebus-Add-beaglebone-geiger-cape.patch b/patches/linux-3.7-rc6/0136-capebus-Add-beaglebone-geiger-cape.patch new file mode 100644 index 0000000..b927473 --- /dev/null +++ b/patches/linux-3.7-rc6/0136-capebus-Add-beaglebone-geiger-cape.patch @@ -0,0 +1,546 @@ +From fbcfeae4d5b070b1300d5b42036a5714fc35cd34 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Tue, 30 Oct 2012 21:12:20 +0200 +Subject: [PATCH] capebus: Add beaglebone geiger cape + +--- + drivers/capebus/capes/Kconfig | 7 + + drivers/capebus/capes/Makefile | 1 + + drivers/capebus/capes/bone-geiger-cape.c | 506 ++++++++++++++++++++++++++++++ + 3 files changed, 514 insertions(+) + create mode 100644 drivers/capebus/capes/bone-geiger-cape.c + +diff --git a/drivers/capebus/capes/Kconfig b/drivers/capebus/capes/Kconfig +index bfe54a6..0418bef 100644 +--- a/drivers/capebus/capes/Kconfig ++++ b/drivers/capebus/capes/Kconfig +@@ -4,3 +4,10 @@ config CAPEBUS_BONE_GENERIC + default n + help + "Select this to enable a generic cape driver; LCD/DVI capes etc" ++ ++config CAPEBUS_BONE_GEIGER ++ tristate "Beaglebone Geiger cape driver" ++ depends on CAPEBUS_BONE_CONTROLLER ++ default n ++ help ++ "Select this to enable a driver for the geiger cape" +diff --git a/drivers/capebus/capes/Makefile b/drivers/capebus/capes/Makefile +index 83da381..d6f94ce 100644 +--- a/drivers/capebus/capes/Makefile ++++ b/drivers/capebus/capes/Makefile +@@ -1 +1,2 @@ + obj-$(CONFIG_CAPEBUS_BONE_GENERIC) += bone-generic-cape.o ++obj-$(CONFIG_CAPEBUS_BONE_GEIGER) += bone-geiger-cape.o +diff --git a/drivers/capebus/capes/bone-geiger-cape.c b/drivers/capebus/capes/bone-geiger-cape.c +new file mode 100644 +index 0000000..880eaae +--- /dev/null ++++ b/drivers/capebus/capes/bone-geiger-cape.c +@@ -0,0 +1,506 @@ ++/* ++ * Driver for beaglebone Geiger cape ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/string.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/bitops.h> ++#include <linux/err.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_gpio.h> ++#include <linux/pinctrl/pinctrl.h> ++#include <linux/pinctrl/pinmux.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/atomic.h> ++#include <linux/clk.h> ++#include <linux/interrupt.h> ++#include <asm/barrier.h> ++#include <plat/clock.h> ++#include <plat/omap_device.h> ++#include <linux/clkdev.h> ++#include <linux/pwm.h> ++#include <linux/math64.h> ++#include <linux/atomic.h> ++#include <linux/leds.h> ++#include <linux/input/ti_am335x_tsc.h> ++#include <linux/platform_data/ti_am335x_adc.h> ++#include <linux/mfd/ti_am335x_tscadc.h> ++#include <plat/omap_device.h> ++#include <linux/iio/iio.h> ++#include <linux/iio/machine.h> ++#include <linux/iio/consumer.h> ++ ++#include <linux/capebus/capebus-bone.h> ++ ++/* fwd decl. */ ++extern struct cape_driver bonegeiger_driver; ++ ++struct bone_geiger_info { ++ struct cape_dev *dev; ++ struct bone_capebus_generic_info *geninfo; ++ struct pwm_device *pwm_dev; ++ int pwm_frequency; ++ int pwm_duty_cycle; ++ int run; ++ atomic64_t counter; ++ int event_gpio; ++ int event_irq; ++ struct led_trigger *event_led; /* event detect */ ++ struct led_trigger *run_led; /* running */ ++ unsigned long event_blink_delay; ++ struct sysfs_dirent *counter_sd; /* notifier */ ++ const char *vsense_name; ++ unsigned int vsense_scale; ++ struct iio_channel *vsense_channel; ++}; ++ ++static const struct of_device_id bonegeiger_of_match[] = { ++ { ++ .compatible = "bone-geiger-cape", ++ }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, bonegeiger_of_match); ++ ++static int bonegeiger_start(struct cape_dev *dev) ++{ ++ struct bone_geiger_info *info = dev->drv_priv; ++ int duty, period; ++ ++ if (info->run != 0) ++ return 0; ++ ++ /* checks */ ++ if (info->pwm_frequency < 1000 || info->pwm_frequency > 50000) { ++ dev_err(&dev->dev, "Cowardly refusing to use a " ++ "frequency of %d\n", ++ info->pwm_frequency); ++ return -EINVAL; ++ } ++ if (info->pwm_duty_cycle > 80) { ++ dev_err(&dev->dev, "Cowardly refusing to use a " ++ "duty cycle of %d\n", ++ info->pwm_duty_cycle); ++ return -EINVAL; ++ } ++ ++ period = div_u64(1000000000LLU, info->pwm_frequency); ++ duty = (period * info->pwm_duty_cycle) / 100; ++ ++ dev_info(&dev->dev, "starting geiger tube with " ++ "duty=%duns period=%dus\n", ++ duty, period); ++ ++ pwm_config(info->pwm_dev, duty, period); ++ pwm_enable(info->pwm_dev); ++ ++ info->run = 1; ++ led_trigger_event(info->run_led, LED_FULL); ++ ++ return 0; ++} ++ ++static int bonegeiger_stop(struct cape_dev *dev) ++{ ++ struct bone_geiger_info *info = dev->drv_priv; ++ ++ if (info->run == 0) ++ return 0; ++ ++ dev_info(&dev->dev, "disabling geiger tube\n"); ++ pwm_config(info->pwm_dev, 0, 50000); /* 0% duty cycle, 20KHz */ ++ pwm_disable(info->pwm_dev); ++ ++ info->run = 0; ++ led_trigger_event(info->run_led, LED_OFF); ++ ++ return 0; ++} ++ ++static ssize_t bonegeiger_show_run(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct cape_dev *cdev = to_cape_dev(dev); ++ struct bone_geiger_info *info = cdev->drv_priv; ++ ++ return sprintf(buf, "%d\n", info->run); ++} ++ ++static ssize_t bonegeiger_store_run(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct cape_dev *cdev = to_cape_dev(dev); ++ int run, err; ++ ++ if (sscanf(buf, "%i", &run) != 1) ++ return -EINVAL; ++ ++ if (run) ++ err = bonegeiger_start(cdev); ++ else ++ err = bonegeiger_stop(cdev); ++ ++ return err ? err : count; ++} ++ ++static ssize_t bonegeiger_show_counter(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct cape_dev *cdev = to_cape_dev(dev); ++ struct bone_geiger_info *info = cdev->drv_priv; ++ ++ return sprintf(buf, "%llu\n", atomic64_read(&info->counter)); ++} ++ ++static ssize_t bonegeiger_store_counter(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct cape_dev *cdev = to_cape_dev(dev); ++ struct bone_geiger_info *info = cdev->drv_priv; ++ ++ atomic64_set(&info->counter, 0); /* just reset */ ++ return count; ++} ++ ++static ssize_t bonegeiger_show_vsense(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct cape_dev *cdev = to_cape_dev(dev); ++ struct bone_geiger_info *info = cdev->drv_priv; ++ int ret, val; ++ u32 mvolts; ++ ++ ret = iio_read_channel_raw(info->vsense_channel, &val); ++ if (ret < 0) ++ return ret; ++ ++ /* V = (1800 / 4096) * val * scale) = (1.8 * val * scale / 4096) */ ++ mvolts = div_u64(1800 * info->vsense_scale * (u64)val, 4096 * 100); ++ ++ return sprintf(buf, "%d\n", mvolts); ++} ++ ++static DEVICE_ATTR(run, S_IRUGO | S_IWUSR, ++ bonegeiger_show_run, bonegeiger_store_run); ++static DEVICE_ATTR(counter, S_IRUGO | S_IWUSR, ++ bonegeiger_show_counter, bonegeiger_store_counter); ++static DEVICE_ATTR(vsense, S_IRUGO, ++ bonegeiger_show_vsense, NULL); ++ ++static int bonegeiger_sysfs_register(struct cape_dev *cdev) ++{ ++ int err; ++ ++ err = device_create_file(&cdev->dev, &dev_attr_run); ++ if (err != 0) ++ goto err_no_run; ++ ++ err = device_create_file(&cdev->dev, &dev_attr_counter); ++ if (err != 0) ++ goto err_no_counter; ++ ++ err = device_create_file(&cdev->dev, &dev_attr_vsense); ++ if (err != 0) ++ goto err_no_vsense; ++ ++ return 0; ++ ++err_no_vsense: ++ device_remove_file(&cdev->dev, &dev_attr_counter); ++err_no_counter: ++ device_remove_file(&cdev->dev, &dev_attr_run); ++err_no_run: ++ return err; ++} ++ ++static void bonegeiger_sysfs_unregister(struct cape_dev *cdev) ++{ ++ device_remove_file(&cdev->dev, &dev_attr_vsense); ++ device_remove_file(&cdev->dev, &dev_attr_counter); ++ device_remove_file(&cdev->dev, &dev_attr_run); ++} ++ ++static irqreturn_t bonegeiger_irq_handler(int irq, void *dev_id) ++{ ++ struct cape_dev *dev = dev_id; ++ struct bone_geiger_info *info = dev->drv_priv; ++ ++ atomic64_inc(&info->counter); ++ ++ led_trigger_blink_oneshot(info->event_led, ++ &info->event_blink_delay, &info->event_blink_delay, 0); ++ ++ sysfs_notify_dirent(info->counter_sd); ++ ++ return IRQ_HANDLED; ++} ++ ++static int bonegeiger_probe(struct cape_dev *dev, const struct cape_device_id *id) ++{ ++ char boardbuf[33]; ++ char versionbuf[5]; ++ const char *board_name; ++ const char *version; ++ struct bone_geiger_info *info; ++ struct pinctrl *pinctrl; ++ struct device_node *node, *pwm_node; ++ phandle phandle; ++ u32 val; ++ int err; ++ ++ /* boiler plate probing */ ++ err = bone_capebus_probe_prolog(dev, id); ++ if (err != 0) ++ return err; ++ ++ /* get the board name (after check of cntrlboard match) */ ++ board_name = bone_capebus_id_get_field(id, BONE_CAPEBUS_BOARD_NAME, ++ boardbuf, sizeof(boardbuf)); ++ /* get the board version */ ++ version = bone_capebus_id_get_field(id, BONE_CAPEBUS_VERSION, ++ versionbuf, sizeof(versionbuf)); ++ /* should never happen; but check anyway */ ++ if (board_name == NULL || version == NULL) ++ return -ENODEV; ++ ++ dev->drv_priv = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL); ++ if (dev->drv_priv == NULL) { ++ dev_err(&dev->dev, "Failed to allocate info\n"); ++ err = -ENOMEM; ++ goto err_no_mem; ++ } ++ info = dev->drv_priv; ++ ++ pinctrl = devm_pinctrl_get_select_default(&dev->dev); ++ if (IS_ERR(pinctrl)) ++ dev_warn(&dev->dev, ++ "pins are not configured from the driver\n"); ++ ++ node = capebus_of_find_property_node(dev, "version", version, "pwms"); ++ if (node == NULL) { ++ dev_err(&dev->dev, "unable to find pwms property\n"); ++ err = -ENODEV; ++ goto err_no_pwm; ++ } ++ ++ err = of_property_read_u32(node, "pwms", &val); ++ if (err != 0) { ++ dev_err(&dev->dev, "unable to read pwm handle\n"); ++ goto err_no_pwm; ++ } ++ phandle = val; ++ ++ pwm_node = of_find_node_by_phandle(phandle); ++ if (pwm_node == NULL) { ++ dev_err(&dev->dev, "Failed to pwm node\n"); ++ err = -EINVAL; ++ goto err_no_pwm; ++ } ++ ++ err = capebus_of_platform_device_enable(pwm_node); ++ of_node_put(pwm_node); ++ if (err != 0) { ++ dev_err(&dev->dev, "Failed to pwm node\n"); ++ goto err_no_pwm; ++ } ++ ++ info->pwm_dev = of_pwm_request(node, NULL); ++ of_node_put(node); ++ if (IS_ERR(info->pwm_dev)) { ++ dev_err(&dev->dev, "unable to request PWM\n"); ++ err = PTR_ERR(info->pwm_dev); ++ goto err_no_pwm; ++ } ++ ++ if (capebus_of_property_read_u32(dev, ++ "version", version, ++ "pwm-frequency", &val) != 0) { ++ val = 20000; ++ dev_warn(&dev->dev, "Could not read pwm-frequency property; " ++ "using default %u\n", ++ val); ++ } ++ info->pwm_frequency = val; ++ ++ if (capebus_of_property_read_u32(dev, ++ "version", version, ++ "pwm-duty-cycle", &val) != 0) { ++ val = 60; ++ dev_warn(&dev->dev, "Could not read pwm-duty-cycle property; " ++ "using default %u\n", ++ val); ++ } ++ info->pwm_duty_cycle = val; ++ ++ node = capebus_of_find_property_node(dev, "gpios", version, "pwms"); ++ info->event_gpio = of_get_gpio_flags(node, 0, NULL); ++ of_node_put(node); ++ if (IS_ERR_VALUE(info->event_gpio)) { ++ dev_err(&dev->dev, "unable to get event GPIO\n"); ++ err = info->event_gpio; ++ goto err_no_gpio; ++ } ++ ++ err = gpio_request_one(info->event_gpio, ++ GPIOF_DIR_IN | GPIOF_EXPORT, ++ "bone-geiger-cape-event"); ++ if (err != 0) { ++ dev_err(&dev->dev, "failed to request event GPIO\n"); ++ goto err_no_gpio; ++ } ++ ++ atomic64_set(&info->counter, 0); ++ ++ info->event_irq = gpio_to_irq(info->event_gpio); ++ if (IS_ERR_VALUE(info->event_irq)) { ++ dev_err(&dev->dev, "unable to get event GPIO IRQ\n"); ++ err = info->event_irq; ++ goto err_no_irq; ++ } ++ ++ err = request_irq(info->event_irq, bonegeiger_irq_handler, ++ IRQF_TRIGGER_RISING | IRQF_SHARED, ++ "bone-geiger-irq", dev); ++ if (err != 0) { ++ dev_err(&dev->dev, "unable to request irq\n"); ++ goto err_no_irq; ++ } ++ ++ err = bonegeiger_sysfs_register(dev); ++ if (err != 0) { ++ dev_err(&dev->dev, "unable to register sysfs\n"); ++ goto err_no_sysfs; ++ } ++ ++ info->counter_sd = sysfs_get_dirent(dev->dev.kobj.sd, NULL, "counter"); ++ if (info->counter_sd == NULL) { ++ dev_err(&dev->dev, "unable to get dirent of counter\n"); ++ err = -ENODEV; ++ goto err_no_counter_dirent; ++ } ++ ++ led_trigger_register_simple("geiger-event", &info->event_led); ++ led_trigger_register_simple("geiger-run", &info->run_led); ++ ++ /* pick up the generics; tsc & leds */ ++ info->geninfo = bone_capebus_probe_generic(dev, id); ++ if (info->geninfo == NULL) { ++ dev_err(&dev->dev, "Could not probe generic\n"); ++ goto err_no_generic; ++ } ++ ++ led_trigger_event(info->run_led, LED_OFF); ++ ++ /* default */ ++ if (capebus_of_property_read_u32(dev, ++ "version", version, ++ "event-blink-delay", &val) != 0) { ++ val = 30; ++ dev_warn(&dev->dev, "Could not read event-blink-delay " ++ "property; using default %u\n", ++ val); ++ } ++ info->event_blink_delay = val; ++ ++ /* default */ ++ if (capebus_of_property_read_string(dev, ++ "version", version, ++ "vsense-name", &info->vsense_name) != 0) { ++ info->vsense_name = "AIN5"; ++ dev_warn(&dev->dev, "Could not read vsense-name property; " ++ "using default %u\n", ++ val); ++ } ++ ++ if (capebus_of_property_read_u32(dev, ++ "version", version, ++ "vsense-scale", &info->vsense_scale) != 0) { ++ info->vsense_scale = 37325; /* 373.25 */ ++ dev_warn(&dev->dev, "Could not read vsense-scale property; " ++ "using default %u\n", ++ info->vsense_scale); ++ } ++ ++ info->vsense_channel = iio_channel_get(NULL, info->vsense_name); ++ if (IS_ERR(info->vsense_channel)) { ++ dev_err(&dev->dev, "Could not get AIN5 analog input\n"); ++ err = PTR_ERR(info->vsense_channel); ++ goto err_no_vsense; ++ } ++ ++ dev_info(&dev->dev, "ready\n"); ++ ++ err = bonegeiger_start(dev); ++ if (err != 0) { ++ dev_err(&dev->dev, "Could not start geiger device\n"); ++ goto err_no_start; ++ } ++ ++ return 0; ++ ++err_no_start: ++ iio_channel_release(info->vsense_channel); ++err_no_vsense: ++ bone_capebus_remove_generic(info->geninfo); ++err_no_generic: ++ led_trigger_unregister_simple(info->run_led); ++ led_trigger_unregister_simple(info->event_led); ++ sysfs_put(info->counter_sd); ++err_no_counter_dirent: ++ bonegeiger_sysfs_unregister(dev); ++err_no_sysfs: ++ free_irq(info->event_irq, dev); ++err_no_irq: ++ gpio_free(info->event_gpio); ++err_no_gpio: ++ pwm_put(info->pwm_dev); ++err_no_pwm: ++ devm_kfree(&dev->dev, info); ++err_no_mem: ++ return err; ++} ++ ++static void bonegeiger_remove(struct cape_dev *dev) ++{ ++ struct bone_geiger_info *info = dev->drv_priv; ++ ++ dev_info(&dev->dev, "Removing geiger cape driver...\n"); ++ ++ bonegeiger_stop(dev); ++ ++ iio_channel_release(info->vsense_channel); ++ bone_capebus_remove_generic(info->geninfo); ++ led_trigger_unregister_simple(info->run_led); ++ led_trigger_unregister_simple(info->event_led); ++ sysfs_put(info->counter_sd); ++ bonegeiger_sysfs_unregister(dev); ++ free_irq(info->event_irq, dev); ++ gpio_free(info->event_gpio); ++ pwm_put(info->pwm_dev); ++} ++ ++struct cape_driver bonegeiger_driver = { ++ .driver = { ++ .name = "bonegeiger", ++ .owner = THIS_MODULE, ++ .of_match_table = bonegeiger_of_match, ++ }, ++ .probe = bonegeiger_probe, ++ .remove = bonegeiger_remove, ++}; ++ ++module_capebus_driver(bonegeiger_driver); ++ ++MODULE_AUTHOR("Pantelis Antoniou"); ++MODULE_DESCRIPTION("Beaglebone geiger cape"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:bone-geiger-cape"); diff --git a/patches/linux-3.7-rc6/0137-capebus-Beaglebone-capebus-DT-update.patch b/patches/linux-3.7-rc6/0137-capebus-Beaglebone-capebus-DT-update.patch new file mode 100644 index 0000000..6bd80a7 --- /dev/null +++ b/patches/linux-3.7-rc6/0137-capebus-Beaglebone-capebus-DT-update.patch @@ -0,0 +1,745 @@ +From 7433fff737ca214acb70407dfec888312a19057f Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Tue, 30 Oct 2012 21:16:57 +0200 +Subject: [PATCH] capebus: Beaglebone capebus DT update + +--- + arch/arm/boot/dts/am335x-bone-common.dtsi | 689 +++++++++++++++++++++++++++-- + 1 file changed, 659 insertions(+), 30 deletions(-) + +diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi +index 99240a5..46d5f27 100644 +--- a/arch/arm/boot/dts/am335x-bone-common.dtsi ++++ b/arch/arm/boot/dts/am335x-bone-common.dtsi +@@ -51,6 +51,143 @@ + 0x60 0x17 /* gpmc_a8.gpio1_24, OUTPUT_PULLUP | MODE7 */ + >; + }; ++ i2c2_pins: pinmux_i2c2_pins { ++ pinctrl-single,pins = < ++ 0x178 0x73 /* uart1_ctsn.i2c2_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */ ++ 0x17c 0x73 /* uart1_rtsn.i2c2_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */ ++ >; ++ }; ++ ++ bone_dvi_cape_led_pins: pinmux_bone_dvi_cape_led_pins { ++ pinctrl-single,pins = < ++ 0x48 0x07 /* gpmc_a2.gpio1_18, OUTPUT | MODE7 */ ++ 0x4c 0x07 /* gpmc_a3.gpio1_19, OUTPUT | MODE7 */ ++ >; ++ }; ++ ++ bone_dvi_cape_dvi_00A0_pins: pinmux_bone_dvi_cape_dvi_00A0_pins { ++ pinctrl-single,pins = < ++ 0x1c 0x07 /* gpmc_ad7.gpio1_7, OUTPUT | MODE7 - DVIPDn */ ++ ++ 0xa0 0x08 /* lcd_data0.lcd_data0, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xa4 0x08 /* lcd_data1.lcd_data1, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xa8 0x08 /* lcd_data2.lcd_data2, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xac 0x08 /* lcd_data3.lcd_data3, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xb0 0x08 /* lcd_data4.lcd_data4, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xb4 0x08 /* lcd_data5.lcd_data5, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xb8 0x08 /* lcd_data6.lcd_data6, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xbc 0x08 /* lcd_data7.lcd_data7, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xc0 0x08 /* lcd_data8.lcd_data8, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xc4 0x08 /* lcd_data9.lcd_data9, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xc8 0x08 /* lcd_data10.lcd_data10, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xcc 0x08 /* lcd_data11.lcd_data11, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xd0 0x08 /* lcd_data12.lcd_data12, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xd4 0x08 /* lcd_data13.lcd_data13, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xd8 0x08 /* lcd_data14.lcd_data14, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xdc 0x08 /* lcd_data15.lcd_data15, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xe0 0x00 /* lcd_vsync.lcd_vsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */ ++ 0xe4 0x00 /* lcd_hsync.lcd_hsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */ ++ 0xe8 0x00 /* lcd_pclk.lcd_pclk, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */ ++ 0xec 0x00 /* lcd_ac_bias_en.lcd_ac_bias_en, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */ ++ >; ++ }; ++ ++ bone_dvi_cape_dvi_00A1_pins: pinmux_bone_dvi_cape_dvi_00A1_pins { ++ pinctrl-single,pins = < ++ 0x84 0x07 /* gpmc_csn2.gpio1_31, OUTPUT | MODE7 - DVIPDn */ ++ ++ 0xa0 0x08 /* lcd_data0.lcd_data0, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xa4 0x08 /* lcd_data1.lcd_data1, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xa8 0x08 /* lcd_data2.lcd_data2, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xac 0x08 /* lcd_data3.lcd_data3, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xb0 0x08 /* lcd_data4.lcd_data4, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xb4 0x08 /* lcd_data5.lcd_data5, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xb8 0x08 /* lcd_data6.lcd_data6, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xbc 0x08 /* lcd_data7.lcd_data7, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xc0 0x08 /* lcd_data8.lcd_data8, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xc4 0x08 /* lcd_data9.lcd_data9, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xc8 0x08 /* lcd_data10.lcd_data10, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xcc 0x08 /* lcd_data11.lcd_data11, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xd0 0x08 /* lcd_data12.lcd_data12, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xd4 0x08 /* lcd_data13.lcd_data13, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xd8 0x08 /* lcd_data14.lcd_data14, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xdc 0x08 /* lcd_data15.lcd_data15, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xe0 0x00 /* lcd_vsync.lcd_vsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */ ++ 0xe4 0x00 /* lcd_hsync.lcd_hsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */ ++ 0xe8 0x00 /* lcd_pclk.lcd_pclk, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */ ++ 0xec 0x00 /* lcd_ac_bias_en.lcd_ac_bias_en, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */ ++ >; ++ }; ++ ++ bone_geiger_cape_led_pins: pinmux_bone_geiger_cape_led_pins { ++ pinctrl-single,pins = < ++ 0xe4 0x07 /* lcd_hsync.gpio2_23, OUTPUT | MODE7 */ ++ 0xec 0x07 /* lcd_ac_bias_en.gpio2_25, OUTPUT | MODE7 */ ++ >; ++ }; ++ ++ bone_geiger_cape_pins: pinmux_bone_geiger_cape_pins { ++ pinctrl-single,pins = < ++ 0x48 0x06 /* gpmc_a2.ehrpwm1a, OMAP_MUX_MODE6 | AM33XX_PIN_OUTPUT */ ++ /* 0x19c 0x34 */ /* mcasp0_ahclkr.eCAP2_in_PWM2_out, OMAP_MUX_MODE4 | INPUT_PULLUP */ ++ 0x19c 0x37 /* mcasp0_ahclkr.gpio3_17, OMAP_MUX_MODE4 | INPUT_PULLUP */ ++ >; ++ }; ++ ++ bone_lcd3_cape_led_00A0_pins: pinmux_bone_lcd3_cape_led_00A0_pins { ++ pinctrl-single,pins = < ++ 0x48 0x07 /* gpmc_a2.gpio1_18, OUTPUT | MODE7 */ ++ 0x4c 0x07 /* gpmc_a3.gpio1_19, OUTPUT | MODE7 */ ++ >; ++ }; ++ ++ bone_lcd3_cape_lcd_pins: pinmux_bone_lcd3_cape_lcd_pins { ++ pinctrl-single,pins = < ++ 0xa0 0x08 /* lcd_data0.lcd_data0, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xa4 0x08 /* lcd_data1.lcd_data1, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xa8 0x08 /* lcd_data2.lcd_data2, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xac 0x08 /* lcd_data3.lcd_data3, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xb0 0x08 /* lcd_data4.lcd_data4, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xb4 0x08 /* lcd_data5.lcd_data5, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xb8 0x08 /* lcd_data6.lcd_data6, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xbc 0x08 /* lcd_data7.lcd_data7, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xc0 0x08 /* lcd_data8.lcd_data8, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xc4 0x08 /* lcd_data9.lcd_data9, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xc8 0x08 /* lcd_data10.lcd_data10, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xcc 0x08 /* lcd_data11.lcd_data11, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xd0 0x08 /* lcd_data12.lcd_data12, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xd4 0x08 /* lcd_data13.lcd_data13, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xd8 0x08 /* lcd_data14.lcd_data14, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xdc 0x08 /* lcd_data15.lcd_data15, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */ ++ 0xe0 0x00 /* lcd_vsync.lcd_vsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */ ++ 0xe4 0x00 /* lcd_hsync.lcd_hsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */ ++ 0xe8 0x00 /* lcd_pclk.lcd_pclk, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */ ++ 0xec 0x00 /* lcd_ac_bias_en.lcd_ac_bias_en, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */ ++ >; ++ }; ++ ++ bone_lcd3_cape_keys_00A0_pins: pinmux_bone_lcd3_cape_keys_00A0_pins { ++ pinctrl-single,pins = < ++ 0x040 0x2f /* gpmc_a0.gpio1_16, INPUT | PULLDIS | MODE7 */ ++ 0x044 0x2f /* gpmc_a1.gpio1_17, INPUT | PULLDIS | MODE7 */ ++ 0x1a4 0x2f /* mcasp0_fsr.gpio3_19, INPUT | PULLDIS | MODE7 */ ++ 0x078 0x2f /* gpmc_ben1.gpio1_28, INPUT | PULLDIS | MODE7 */ ++ 0x164 0x2f /* ecap0_in_pwm0_out.gpio0_7, INPUT | PULLDIS | MODE7 */ ++ >; ++ }; ++ ++ pwm_bl_pins: pinmux_pwm_bl_pins { ++ pinctrl-single,pins = < ++ 0x4c 0x06 /* gpmc_a3.ehrpwm1b, OMAP_MUX_MODE6 | AM33XX_PIN_OUTPUT */ ++ // 0x48 0x06 /* gpmc_a2.ehrpwm1a, OMAP_MUX_MODE6 | AM33XX_PIN_OUTPUT */ ++ >; ++ }; ++ ++ weather_cape_w1_pins: pinmux_weather_cape_w1_pins { ++ pinctrl-single,pins = < ++ 0x0c 0x37 /* gpmc_ad3.gpio1_3, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE7 - w1-gpio */ ++ >; ++ }; + }; + + ocp { +@@ -92,16 +229,6 @@ + }; + }; + +- i2c1: i2c@44e0b000 { +- status = "okay"; +- clock-frequency = <400000>; +- +- tps: tps@24 { +- reg = <0x24>; +- }; +- +- }; +- + gpevt { + compatible = "gpevt"; + pinctrl-names = "default"; +@@ -110,15 +237,117 @@ + dma-names = "gpioevt"; + gpio-evt = <&gpio3 2 0>; + }; ++ ++ }; ++ ++ capebus: capebus@0 { ++ compatible = "bone-capebus"; ++ ++ bone_dvi_cape: cape@0 { ++ compatible = "bone-generic-cape"; ++ }; ++ ++ bone_geiger_cape: cape@1 { ++ compatible = "bone-geiger-cape"; ++ }; ++ ++ bone_lcd3_cape: cape@2 { ++ compatible = "bone-generic-cape"; ++ }; ++ ++ bone_lcd7_cape: cape@3 { ++ compatible = "bone-lcd7-cape"; ++ }; ++ ++ bone_weather_cape: cape@4 { ++ compatible = "bone-generic-cape"; ++ }; ++ ++ bone_adafruit_cape: cape@5 { ++ compatible = "bone-generic-cape"; ++ }; ++ ++ /* overrides; no EEPROM (prototyping) */ ++// override@3 { ++// compatible = "bone-capebus-slot-override"; ++// slot = <3>; ++// board-name = "Geiger Cape"; ++// version = "00A0"; ++// manufacturer = "Geiger Inc"; ++// /* TODO: Add the rest */ ++// }; ++ ++// override@2 { ++// compatible = "bone-capebus-slot-override"; ++// slot = <2>; ++// board-name = "Weather Cape"; ++// version = "00A0"; ++// manufacturer = "CCO Inc"; ++// /* TODO: Add the rest */ ++// }; ++ ++// override@1 { ++// compatible = "bone-capebus-slot-override"; ++// slot = <1>; ++// board-name = "Adafruit 1.8 Cape"; ++// version = "00A0"; ++// manufacturer = "Adafruit"; ++// /* TODO: Add the rest */ ++// }; ++ ++// override@0 { ++// compatible = "bone-capebus-slot-override"; ++// slot = <0>; ++// board-name = "BeagleBone Weather CAPE"; ++// version = "00A0"; ++// manufacturer = "Beagleboardtoys"; ++// /* TODO: Add the rest */ ++// }; + }; + +- backlight { +- compatible = "pwm-backlight"; +- pwms = <&ehrpwm1 0 500000 0>; +- pwm-names = "st7735fb"; +- brightness-levels = <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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100>; +- default-brightness-level = <50>; /* index to the array above */ +- }; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ ++ tps: tps@24 { ++ reg = <0x24>; ++ }; ++ ++ baseboard_eeprom: baseboard_eeprom@50 { ++ compatible = "at,24c256"; ++ reg = <0x50>; ++ }; ++}; ++ ++&i2c2 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_pins>; ++ ++ clock-frequency = <100000>; ++ ++ /* OK, I know these are cape but for now it will do */ ++ cape_eeprom_0: cape_eeprom_0@54 { ++ compatible = "at,24c256"; ++ reg = <0x54>; ++ }; ++ ++ cape_eeprom_1: cape_eeprom_1@55 { ++ compatible = "at,24c256"; ++ reg = <0x55>; ++ }; ++ ++ cape_eeprom_2: cape_eeprom_2@56 { ++ compatible = "at,24c256"; ++ reg = <0x56>; ++ }; ++ ++ cape_eeprom_3: cape_eeprom_3@57 { ++ compatible = "at,24c256"; ++ reg = <0x57>; ++ }; + }; + + /include/ "tps65217.dtsi" +@@ -165,6 +394,7 @@ + regulator-always-on; + }; + }; ++ + }; + + &mmc1 { +@@ -172,21 +402,8 @@ + }; + + &spi1 { +- status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&spi1_pins>; +- +- lcd@0 { +- compatible = "adafruit,tft-lcd-1.8-green", "sitronix,st7735"; +- spi-max-frequency = <8000000>; +- reg = <0>; +- spi-cpol; +- spi-cpha; +- pinctrl-names = "default"; +- pinctrl-0 = <&lcd_pins>; +- st7735-rst = <&gpio4 19 0>; +- st7735-dc = <&gpio4 21 0>; +- }; + }; + + &edma { +@@ -200,3 +417,415 @@ + &cpsw_emac1 { + phy_id = "4a101000.mdio:01"; + }; ++ ++&ehrpwm1 { ++ status = "okay"; ++}; ++ ++&capebus { ++ slots = <&cape_eeprom_0 &cape_eeprom_1 &cape_eeprom_2 &cape_eeprom_3>; ++}; ++ ++&bone_dvi_cape { ++ board-name = "BeagleBone DVI-D CAPE"; ++ ++ /* hacky, since this is not a proper DT platform device */ ++ /* but until we have DT bindings... */ ++ version@00A0 { ++ version = "00A0"; ++ dvi { ++ compatible = "da8xx-dt"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bone_dvi_cape_dvi_00A0_pins>; ++ ti,hwmods = "lcdc"; ++ ++ disp-pll = <560000000>; ++ panel-type = "1024x768@60"; ++ powerdn-gpio = <&gpio2 7 0>; ++ }; ++ }; ++ ++ version@00A1 { ++ version = "00A1", "01"; ++ dvi { ++ compatible = "da8xx-dt"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bone_dvi_cape_dvi_00A1_pins>; ++ ti,hwmods = "lcdc"; ++ ++ disp-pll = <560000000>; ++ panel-type = "1024x768@60"; ++ powerdn-gpio = <&gpio2 31 0>; ++ }; ++ }; ++ ++ gpio-leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bone_dvi_cape_led_pins>; ++ ++ dvi-led0 { ++ label = "dvi:green:usr0"; ++ gpios = <&gpio2 18 0>; ++ linux,default-trigger = "heartbeat"; ++ default-state = "off"; ++ }; ++ ++ dvi-led1 { ++ label = "dvi:green:usr1"; ++ gpios = <&gpio2 19 0>; ++ linux,default-trigger = "mmc0"; ++ default-state = "off"; ++ }; ++ }; ++}; ++ ++&bone_geiger_cape { ++ board-name = "Geiger Cape"; ++ ++ /* note that these can't be versioned... */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bone_geiger_cape_pins>; ++ ++ pwms = <&ehrpwm1 0 500000 0>; ++ pwm-names = "bone-geiger-cape"; ++ ++ pwm-frequency = <20000>; /* 20KHz */ ++ pwm-duty-cycle = <60>; /* 60% */ ++ ++ event-blink-delay = <30>; /* 30ms */ ++ ++ gpios = <&gpio4 17 0>; /* pulse */ ++ ++ vsense-name = "AIN5"; /* analog vsense */ ++ vsense-scale = <37325>; /* scaling */ ++ ++ tscadc { ++ compatible = "ti-tscadc-dt"; ++ ++ ti,hwmods = "adc_tsc"; ++ ++ adc-channels = <8>; ++ }; ++ ++ gpio-leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bone_geiger_cape_led_pins>; ++ ++ geiger-led0 { ++ label = "geiger:green:usr0"; ++ gpios = <&gpio3 23 0>; ++ linux,default-trigger = "geiger-run"; ++ default-state = "off"; ++ }; ++ ++ geiger-led1 { ++ label = "geiger:red:usr1"; ++ gpios = <&gpio3 25 0>; ++ linux,default-trigger = "geiger-event"; ++ default-state = "off"; ++ }; ++ }; ++}; ++ ++&bone_lcd3_cape { ++ board-name = "BeagleBone LCD3 CAPE"; ++ ++ /* hacky, since this is not a proper DT platform device */ ++ /* but until we have DT bindings... */ ++ lcd3 { ++ compatible = "da8xx-dt"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bone_lcd3_cape_lcd_pins>; ++ ++ ti,hwmods = "lcdc"; ++ ++ disp-pll = <16000000>; ++ panel-type = "CDTech_S035Q01"; ++ }; ++ ++ /* same thing as above */ ++ tscadc { ++ compatible = "ti-tscadc-dt"; ++ ++ ti,hwmods = "adc_tsc"; ++ ++ tsc-wires = <4>; ++ tsc-x-plate-resistance = <200>; ++ tsc-steps = <6>; ++ ++ adc-channels = <4>; ++ }; ++ ++ version@00A0 { ++ version = "00A0"; ++ ++ backlight { ++ compatible = "tps65217-backlight"; ++ isel = <1>; ++ fdim = <200>; ++ ++ tps = <&tps>; /* link to the tps */ ++ brightness = <100>; ++ }; ++ ++ gpio-leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bone_lcd3_cape_led_00A0_pins>; ++ ++ lcd3-led0 { ++ label = "lcd3:green:usr0"; ++ gpios = <&gpio2 18 0>; ++ linux,default-trigger = "heartbeat"; ++ default-state = "off"; ++ }; ++ ++ lcd3-led1 { ++ label = "lcd3:green:usr1"; ++ gpios = <&gpio2 19 0>; ++ linux,default-trigger = "cpu0"; ++ default-state = "off"; ++ }; ++ }; ++ ++ gpio_keys { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bone_lcd3_cape_keys_00A0_pins>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ button@1 { ++ debounce_interval = <50>; ++ linux,code = <105>; ++ label = "left"; ++ gpios = <&gpio2 16 0x0>; ++ gpio-key,wakeup; ++ autorepeat; ++ }; ++ button@2 { ++ debounce_interval = <50>; ++ linux,code = <106>; ++ label = "right"; ++ gpios = <&gpio2 17 0x0>; ++ gpio-key,wakeup; ++ autorepeat; ++ }; ++ button@3 { ++ debounce_interval = <50>; ++ linux,code = <103>; ++ label = "up"; ++ gpios = <&gpio4 19 0x0>; ++ gpio-key,wakeup; ++ autorepeat; ++ }; ++ button@4 { ++ debounce_interval = <50>; ++ linux,code = <108>; ++ label = "down"; ++ gpios = <&gpio2 28 0x0>; ++ gpio-key,wakeup; ++ autorepeat; ++ }; ++ button@5 { ++ debounce_interval = <50>; ++ linux,code = <28>; ++ label = "enter"; ++ gpios = <&gpio1 7 0x0>; ++ gpio-key,wakeup; ++ }; ++ }; ++ }; ++}; ++ ++&bone_lcd7_cape { ++ board-name = "BeagleBone LCD7 CAPE"; ++ ++ /* hacky, since this is not a proper DT platform device */ ++ /* but until we have DT bindings... */ ++ lcd7 { ++ compatible = "da8xx-dt"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bone_lcd3_cape_lcd_pins>; ++ ++ ti,hwmods = "lcdc"; ++ ++ disp-pll = <60000000>; ++ panel-type = "TFC_S9700RTWV35TR_01B"; ++ }; ++ ++ /* same thing as above */ ++ tscadc { ++ compatible = "ti-tscadc-dt"; ++ ++ ti,hwmods = "adc_tsc"; ++ ++ tsc-wires = <4>; ++ tsc-x-plate-resistance = <200>; ++ tsc-steps = <6>; ++ ++ adc-channels = <4>; ++ }; ++ ++ version@00A0 { ++ version = "00A0"; ++ ++ backlight { ++ compatible = "tps65217-backlight"; ++ isel = <1>; ++ fdim = <200>; ++ ++ tps = <&tps>; /* link to the tps */ ++ brightness = <100>; ++ }; ++ ++ gpio-leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bone_lcd3_cape_led_00A0_pins>; ++ ++ lcd3-led0 { ++ label = "lcd3:green:usr0"; ++ gpios = <&gpio2 18 0>; ++ linux,default-trigger = "heartbeat"; ++ default-state = "off"; ++ }; ++ ++ lcd3-led1 { ++ label = "lcd3:green:usr1"; ++ gpios = <&gpio2 19 0>; ++ linux,default-trigger = "cpu0"; ++ default-state = "off"; ++ }; ++ }; ++ ++ gpio_keys { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bone_lcd3_cape_keys_00A0_pins>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ button@1 { ++ debounce_interval = <50>; ++ linux,code = <105>; ++ label = "left"; ++ gpios = <&gpio2 16 0x0>; ++ gpio-key,wakeup; ++ autorepeat; ++ }; ++ button@2 { ++ debounce_interval = <50>; ++ linux,code = <106>; ++ label = "right"; ++ gpios = <&gpio2 17 0x0>; ++ gpio-key,wakeup; ++ autorepeat; ++ }; ++ button@3 { ++ debounce_interval = <50>; ++ linux,code = <103>; ++ label = "up"; ++ gpios = <&gpio4 19 0x0>; ++ gpio-key,wakeup; ++ autorepeat; ++ }; ++ button@4 { ++ debounce_interval = <50>; ++ linux,code = <108>; ++ label = "down"; ++ gpios = <&gpio2 28 0x0>; ++ gpio-key,wakeup; ++ autorepeat; ++ }; ++ button@5 { ++ debounce_interval = <50>; ++ linux,code = <28>; ++ label = "enter"; ++ gpios = <&gpio1 7 0x0>; ++ gpio-key,wakeup; ++ }; ++ }; ++ }; ++}; ++ ++&bone_weather_cape { ++ board-name = "BeagleBone Weather CAPE"; ++ ++ i2c2-devices { ++ compatible = "i2c-dt"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ parent = <&i2c2>; ++ ++ /* Ambient light sensor */ ++ tsl2550@39 { ++ compatible = "tsl,tsl2550"; ++ reg = <0x39>; ++ }; ++ ++ /* Humidity Sensor */ ++ sht21@40 { ++ compatible = "sensiron,sht21"; ++ reg = <0x40>; ++ }; ++ ++ /* Barometric pressure sensor */ ++ bmp085@77 { ++ compatible = "bosch,bmp085"; ++ reg = <0x77>; ++ }; ++ }; ++ ++ onewire@0 { ++ compatible = "w1-gpio"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&weather_cape_w1_pins>; ++ status = "okay"; ++ ++ gpios = <&gpio2 3 0>; ++ }; ++ ++}; ++ ++&bone_adafruit_cape { ++ board-name = "Adafruit 1.8 Cape"; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_bl_pins>; ++ ++ pwms = <&ehrpwm1 1 500000 0>; ++ pwm-names = "st7735fb"; ++ brightness-levels = <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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100>; ++ default-brightness-level = <50>; /* index to the array above */ ++ }; ++ ++ spi1-devices { ++ compatible = "spi-dt"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ parent = <&spi1>; ++ ++ lcd@0 { ++ compatible = "adafruit,tft-lcd-1.8-red", "sitronix,st7735"; ++ spi-max-frequency = <8000000>; ++ reg = <0>; ++ spi-cpol; ++ spi-cpha; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&lcd_pins>; ++ st7735-rst = <&gpio4 19 0>; ++ st7735-dc = <&gpio4 21 0>; ++ }; ++ ++ }; ++}; diff --git a/patches/linux-3.7-rc6/0138-beaglebone-Update-default-config-for-capebus.patch b/patches/linux-3.7-rc6/0138-beaglebone-Update-default-config-for-capebus.patch new file mode 100644 index 0000000..49a5602 --- /dev/null +++ b/patches/linux-3.7-rc6/0138-beaglebone-Update-default-config-for-capebus.patch @@ -0,0 +1,3909 @@ +From 116c5c49c91c1638620714ddfb74eb21b79505c3 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <panto@antoniou-consulting.com> +Date: Tue, 30 Oct 2012 21:17:39 +0200 +Subject: [PATCH] beaglebone: Update default config for capebus + +--- + defconfig | 3893 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 3893 insertions(+) + create mode 100644 defconfig + +diff --git a/defconfig b/defconfig +new file mode 100644 +index 0000000..ee51fa1 +--- /dev/null ++++ b/defconfig +@@ -0,0 +1,3893 @@ ++# ++# Automatically generated file; DO NOT EDIT. ++# Linux/arm 3.7.0-rc2 Kernel Configuration ++# ++CONFIG_ARM=y ++CONFIG_SYS_SUPPORTS_APM_EMULATION=y ++CONFIG_GENERIC_GPIO=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_VECTORS_BASE=0xffff0000 ++CONFIG_ARM_PATCH_PHYS_VIRT=y ++CONFIG_NEED_MACH_GPIO_H=y ++CONFIG_GENERIC_BUG=y ++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" ++CONFIG_HAVE_IRQ_WORK=y ++CONFIG_IRQ_WORK=y ++ ++# ++# General setup ++# ++CONFIG_EXPERIMENTAL=y ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++CONFIG_CROSS_COMPILE="" ++CONFIG_LOCALVERSION="" ++CONFIG_LOCALVERSION_AUTO=y ++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 is not set ++# CONFIG_AUDIT 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_GENERIC_IRQ_CHIP=y ++CONFIG_IRQ_DOMAIN=y ++# CONFIG_IRQ_DOMAIN_DEBUG is not set ++CONFIG_SPARSE_IRQ=y ++CONFIG_KTIME_SCALAR=y ++CONFIG_GENERIC_CLOCKEVENTS=y ++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y ++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y ++ ++# ++# Timers subsystem ++# ++CONFIG_TICK_ONESHOT=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=y ++ ++# ++# CPU/Task time and stats accounting ++# ++CONFIG_TICK_CPU_ACCOUNTING=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_BSD_PROCESS_ACCT_V3=y ++CONFIG_TASKSTATS=y ++CONFIG_TASK_DELAY_ACCT=y ++CONFIG_TASK_XACCT=y ++CONFIG_TASK_IO_ACCOUNTING=y ++ ++# ++# RCU Subsystem ++# ++CONFIG_TREE_RCU=y ++# CONFIG_PREEMPT_RCU 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_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_LOG_BUF_SHIFT=17 ++CONFIG_CGROUPS=y ++# CONFIG_CGROUP_DEBUG is not set ++# CONFIG_CGROUP_FREEZER is not set ++# CONFIG_CGROUP_DEVICE is not set ++# CONFIG_CPUSETS is not set ++# CONFIG_CGROUP_CPUACCT is not set ++# CONFIG_RESOURCE_COUNTERS is not set ++# CONFIG_CGROUP_PERF is not set ++CONFIG_CGROUP_SCHED=y ++CONFIG_FAIR_GROUP_SCHED=y ++# CONFIG_CFS_BANDWIDTH is not set ++# CONFIG_RT_GROUP_SCHED is not set ++# CONFIG_BLK_CGROUP is not set ++# CONFIG_CHECKPOINT_RESTORE is not set ++CONFIG_NAMESPACES=y ++CONFIG_UTS_NS=y ++CONFIG_IPC_NS=y ++CONFIG_PID_NS=y ++CONFIG_NET_NS=y ++CONFIG_SCHED_AUTOGROUP=y ++# CONFIG_SYSFS_DEPRECATED is not set ++# CONFIG_RELAY is not set ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_INITRAMFS_SOURCE="" ++CONFIG_RD_GZIP=y ++# CONFIG_RD_BZIP2 is not set ++# CONFIG_RD_LZMA is not set ++# CONFIG_RD_XZ is not set ++# CONFIG_RD_LZO is not set ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_SYSCTL=y ++CONFIG_ANON_INODES=y ++CONFIG_EXPERT=y ++CONFIG_HAVE_UID16=y ++CONFIG_UID16=y ++# CONFIG_SYSCTL_SYSCALL is not set ++CONFIG_KALLSYMS=y ++CONFIG_KALLSYMS_ALL=y ++CONFIG_HOTPLUG=y ++CONFIG_PRINTK=y ++CONFIG_BUG=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 is not set ++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_COMPAT_BRK=y ++CONFIG_SLAB=y ++# CONFIG_SLUB is not set ++# CONFIG_SLOB is not set ++CONFIG_PROFILING=y ++CONFIG_TRACEPOINTS=y ++CONFIG_OPROFILE=m ++CONFIG_HAVE_OPROFILE=y ++CONFIG_KPROBES=y ++# CONFIG_JUMP_LABEL is not set ++CONFIG_KRETPROBES=y ++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_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_GENERIC_KERNEL_THREAD=y ++CONFIG_GENERIC_KERNEL_EXECVE=y ++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y ++CONFIG_MODULES_USE_ELF_REL=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=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_MODULE_FORCE_UNLOAD=y ++CONFIG_MODVERSIONS=y ++CONFIG_MODULE_SRCVERSION_ALL=y ++# 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=y ++ ++# ++# 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=y ++CONFIG_MSDOS_PARTITION=y ++# CONFIG_BSD_DISKLABEL is not set ++# CONFIG_MINIX_SUBPARTITION is not set ++# CONFIG_SOLARIS_X86_PARTITION is not set ++# CONFIG_UNIXWARE_DISKLABEL is not set ++# CONFIG_LDM_PARTITION 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_DEFAULT_DEADLINE is not set ++CONFIG_DEFAULT_CFQ=y ++# CONFIG_DEFAULT_NOOP is not set ++CONFIG_DEFAULT_IOSCHED="cfq" ++CONFIG_PADATA=y ++CONFIG_ASN1=m ++CONFIG_INLINE_SPIN_UNLOCK_IRQ=y ++CONFIG_INLINE_READ_UNLOCK=y ++CONFIG_INLINE_READ_UNLOCK_IRQ=y ++CONFIG_INLINE_WRITE_UNLOCK=y ++CONFIG_INLINE_WRITE_UNLOCK_IRQ=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_BCM2835 is not set ++# CONFIG_ARCH_CNS3XXX is not set ++# CONFIG_ARCH_CLPS711X is not set ++# CONFIG_ARCH_GEMINI is not set ++# CONFIG_ARCH_SIRF is not set ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_EP93XX is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_MXC is not set ++# CONFIG_ARCH_MXS is not set ++# CONFIG_ARCH_NETX is not set ++# CONFIG_ARCH_H720X 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_TEGRA is not set ++# CONFIG_ARCH_PXA is not set ++# 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_U8500 is not set ++# CONFIG_ARCH_NOMADIK is not set ++# CONFIG_PLAT_SPEAR is not set ++# CONFIG_ARCH_DAVINCI is not set ++CONFIG_ARCH_OMAP=y ++# CONFIG_ARCH_VT8500 is not set ++# CONFIG_ARCH_ZYNQ is not set ++# CONFIG_GPIO_PCA953X is not set ++# CONFIG_KEYBOARD_GPIO_POLLED is not set ++ ++# ++# TI OMAP Common Features ++# ++# CONFIG_ARCH_OMAP1 is not set ++CONFIG_ARCH_OMAP2PLUS=y ++ ++# ++# OMAP Feature Selections ++# ++CONFIG_OMAP_RESET_CLOCKS=y ++CONFIG_OMAP_MUX=y ++CONFIG_OMAP_MUX_DEBUG=y ++CONFIG_OMAP_MUX_WARNINGS=y ++# CONFIG_OMAP_MBOX_FWK is not set ++CONFIG_OMAP_32K_TIMER=y ++# CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE is not set ++CONFIG_OMAP_32K_TIMER_HZ=128 ++CONFIG_OMAP_DM_TIMER=y ++CONFIG_OMAP_PM_NOOP=y ++CONFIG_MACH_OMAP_GENERIC=y ++ ++# ++# TI OMAP2/3/4 Specific Features ++# ++CONFIG_ARCH_OMAP2PLUS_TYPICAL=y ++CONFIG_SOC_HAS_OMAP2_SDRC=y ++# CONFIG_SOC_HAS_REALTIME_COUNTER is not set ++# CONFIG_ARCH_OMAP2 is not set ++CONFIG_ARCH_OMAP3=y ++CONFIG_ARCH_OMAP4=y ++# CONFIG_SOC_OMAP5 is not set ++CONFIG_SOC_OMAP3430=y ++# CONFIG_SOC_TI81XX is not set ++CONFIG_SOC_AM33XX=y ++CONFIG_OMAP_PACKAGE_CBB=y ++CONFIG_OMAP_PACKAGE_CBL=y ++CONFIG_OMAP_PACKAGE_CBS=y ++ ++# ++# OMAP Board Type ++# ++CONFIG_MACH_OMAP3_BEAGLE=y ++# CONFIG_MACH_DEVKIT8000 is not set ++# CONFIG_MACH_OMAP_LDP is not set ++# CONFIG_MACH_OMAP3530_LV_SOM is not set ++# CONFIG_MACH_OMAP3_TORPEDO is not set ++# CONFIG_MACH_OVERO is not set ++# CONFIG_MACH_OMAP3EVM is not set ++# CONFIG_MACH_OMAP3517EVM is not set ++# CONFIG_MACH_CRANEBOARD is not set ++# CONFIG_MACH_OMAP3_PANDORA is not set ++# CONFIG_MACH_TOUCHBOOK is not set ++# CONFIG_MACH_OMAP_3430SDP is not set ++# CONFIG_MACH_NOKIA_RM680 is not set ++# CONFIG_MACH_NOKIA_RX51 is not set ++# CONFIG_MACH_OMAP_ZOOM2 is not set ++# CONFIG_MACH_OMAP_ZOOM3 is not set ++# CONFIG_MACH_CM_T35 is not set ++# CONFIG_MACH_CM_T3517 is not set ++CONFIG_MACH_IGEP0020=y ++# CONFIG_MACH_IGEP0030 is not set ++# CONFIG_MACH_SBC3530 is not set ++# CONFIG_MACH_OMAP_3630SDP is not set ++# CONFIG_MACH_OMAP_4430SDP is not set ++CONFIG_MACH_OMAP4_PANDA=y ++# CONFIG_OMAP3_EMU is not set ++# CONFIG_OMAP3_SDRC_AC_TIMING is not set ++# CONFIG_OMAP4_ERRATA_I688 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=y ++# CONFIG_ARM_VIRT_EXT is not set ++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_OUTER_CACHE=y ++CONFIG_OUTER_CACHE_SYNC=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=y ++CONFIG_ARM_ERRATA_720789=y ++CONFIG_PL310_ERRATA_727915=y ++# 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 is not set ++# CONFIG_ARM_ERRATA_754327 is not set ++# CONFIG_ARM_ERRATA_764369 is not set ++# CONFIG_PL310_ERRATA_769419 is not set ++# CONFIG_ARM_ERRATA_775420 is not set ++CONFIG_ARM_GIC=y ++CONFIG_TI_PRIV_EDMA=y ++ ++# ++# 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_ARM_ARCH_TIMER is not set ++CONFIG_HAVE_ARM_TWD=y ++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_LOCAL_TIMERS=y ++CONFIG_ARCH_NR_GPIO=0 ++# CONFIG_PREEMPT_NONE is not set ++CONFIG_PREEMPT_VOLUNTARY=y ++# CONFIG_PREEMPT is not set ++CONFIG_HZ=128 ++CONFIG_THUMB2_KERNEL=y ++CONFIG_THUMB2_AVOID_R_ARM_THM_JUMP11=y ++CONFIG_ARM_ASM_UNIFIED=y ++CONFIG_AEABI=y ++CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=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_SELECT_MEMORY_MODEL=y ++CONFIG_FLATMEM_MANUAL=y ++CONFIG_FLATMEM=y ++CONFIG_FLAT_NODE_MEM_MAP=y ++CONFIG_HAVE_MEMBLOCK=y ++CONFIG_PAGEFLAGS_EXTENDED=y ++CONFIG_SPLIT_PTLOCK_CPUS=4 ++# CONFIG_COMPACTION is not set ++# CONFIG_PHYS_ADDR_T_64BIT is not set ++CONFIG_ZONE_DMA_FLAG=0 ++CONFIG_BOUNCE=y ++CONFIG_VIRT_TO_BUS=y ++# CONFIG_KSM is not set ++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=12 ++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 ++ ++# ++# Boot options ++# ++CONFIG_USE_OF=y ++CONFIG_ATAGS=y ++# CONFIG_DEPRECATED_PARAM_STRUCT is not set ++CONFIG_ZBOOT_ROM_TEXT=0x0 ++CONFIG_ZBOOT_ROM_BSS=0x0 ++CONFIG_ARM_APPENDED_DTB=y ++CONFIG_ARM_ATAG_DTB_COMPAT=y ++CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y ++# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND 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_STAT=y ++CONFIG_CPU_FREQ_STAT_DETAILS=y ++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_CONSERVATIVE is not set ++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y ++CONFIG_CPU_FREQ_GOV_POWERSAVE=y ++CONFIG_CPU_FREQ_GOV_USERSPACE=y ++CONFIG_CPU_FREQ_GOV_ONDEMAND=y ++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y ++CONFIG_GENERIC_CPUFREQ_CPU0=y ++ ++# ++# ARM CPU frequency scaling drivers ++# ++# CONFIG_ARM_OMAP2PLUS_CPUFREQ is not set ++# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set ++# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set ++# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set ++CONFIG_CPU_IDLE=y ++CONFIG_CPU_IDLE_GOV_LADDER=y ++CONFIG_CPU_IDLE_GOV_MENU=y ++CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED=y ++ ++# ++# Floating point emulation ++# ++ ++# ++# At least one emulation must be selected ++# ++CONFIG_VFP=y ++CONFIG_VFPv3=y ++CONFIG_NEON=y ++ ++# ++# Userspace binary formats ++# ++CONFIG_BINFMT_ELF=y ++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y ++CONFIG_HAVE_AOUT=y ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_MISC=y ++# CONFIG_COREDUMP is not set ++ ++# ++# Power management options ++# ++CONFIG_SUSPEND=y ++CONFIG_SUSPEND_FREEZER=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=y ++CONFIG_PM=y ++CONFIG_PM_DEBUG=y ++# CONFIG_PM_ADVANCED_DEBUG is not set ++# CONFIG_PM_TEST_SUSPEND is not set ++CONFIG_PM_SLEEP_DEBUG=y ++# CONFIG_APM_EMULATION is not set ++CONFIG_ARCH_HAS_OPP=y ++CONFIG_PM_OPP=y ++CONFIG_PM_CLK=y ++CONFIG_CPU_PM=y ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++CONFIG_ARM_CPU_SUSPEND=y ++CONFIG_NET=y ++ ++# ++# Networking options ++# ++CONFIG_PACKET=y ++CONFIG_PACKET_DIAG=m ++CONFIG_UNIX=y ++CONFIG_UNIX_DIAG=m ++CONFIG_XFRM=y ++CONFIG_XFRM_ALGO=y ++CONFIG_XFRM_USER=y ++# CONFIG_XFRM_SUB_POLICY is not set ++CONFIG_XFRM_MIGRATE=y ++# CONFIG_XFRM_STATISTICS is not set ++CONFIG_XFRM_IPCOMP=m ++CONFIG_NET_KEY=y ++CONFIG_NET_KEY_MIGRATE=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_ADVANCED_ROUTER=y ++# CONFIG_IP_FIB_TRIE_STATS is not set ++# CONFIG_IP_MULTIPLE_TABLES is not set ++# CONFIG_IP_ROUTE_MULTIPATH is not set ++# CONFIG_IP_ROUTE_VERBOSE is not set ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++CONFIG_IP_PNP_BOOTP=y ++CONFIG_IP_PNP_RARP=y ++CONFIG_NET_IPIP=m ++CONFIG_NET_IPGRE_DEMUX=m ++CONFIG_NET_IPGRE=m ++# CONFIG_NET_IPGRE_BROADCAST is not set ++CONFIG_IP_MROUTE=y ++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y ++CONFIG_IP_PIMSM_V1=y ++CONFIG_IP_PIMSM_V2=y ++CONFIG_ARPD=y ++CONFIG_SYN_COOKIES=y ++# CONFIG_NET_IPVTI is not set ++CONFIG_INET_AH=m ++CONFIG_INET_ESP=m ++CONFIG_INET_IPCOMP=m ++CONFIG_INET_XFRM_TUNNEL=m ++CONFIG_INET_TUNNEL=m ++CONFIG_INET_XFRM_MODE_TRANSPORT=m ++CONFIG_INET_XFRM_MODE_TUNNEL=m ++CONFIG_INET_XFRM_MODE_BEET=m ++CONFIG_INET_LRO=m ++CONFIG_INET_DIAG=y ++CONFIG_INET_TCP_DIAG=y ++CONFIG_INET_UDP_DIAG=m ++CONFIG_TCP_CONG_ADVANCED=y ++CONFIG_TCP_CONG_BIC=m ++CONFIG_TCP_CONG_CUBIC=y ++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_CUBIC=y ++# CONFIG_DEFAULT_RENO is not set ++CONFIG_DEFAULT_TCP_CONG="cubic" ++# CONFIG_TCP_MD5SIG is not set ++CONFIG_IPV6=m ++CONFIG_IPV6_PRIVACY=y ++CONFIG_IPV6_ROUTER_PREF=y ++CONFIG_IPV6_ROUTE_INFO=y ++CONFIG_IPV6_OPTIMISTIC_DAD=y ++CONFIG_INET6_AH=m ++CONFIG_INET6_ESP=m ++CONFIG_INET6_IPCOMP=m ++CONFIG_IPV6_MIP6=m ++CONFIG_INET6_XFRM_TUNNEL=m ++CONFIG_INET6_TUNNEL=m ++CONFIG_INET6_XFRM_MODE_TRANSPORT=m ++CONFIG_INET6_XFRM_MODE_TUNNEL=m ++CONFIG_INET6_XFRM_MODE_BEET=m ++CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m ++CONFIG_IPV6_SIT=m ++# CONFIG_IPV6_SIT_6RD is not set ++CONFIG_IPV6_NDISC_NODETYPE=y ++CONFIG_IPV6_TUNNEL=m ++CONFIG_IPV6_GRE=m ++CONFIG_IPV6_MULTIPLE_TABLES=y ++CONFIG_IPV6_SUBTREES=y ++CONFIG_IPV6_MROUTE=y ++CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y ++CONFIG_IPV6_PIMSM_V2=y ++# CONFIG_NETLABEL is not set ++# CONFIG_NETWORK_SECMARK is not set ++# 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_ACCT is not set ++# CONFIG_NETFILTER_NETLINK_QUEUE is not set ++# CONFIG_NETFILTER_NETLINK_LOG is not set ++# CONFIG_NF_CONNTRACK is not set ++# CONFIG_NETFILTER_TPROXY is not set ++CONFIG_NETFILTER_XTABLES=m ++ ++# ++# Xtables combined modules ++# ++# CONFIG_NETFILTER_XT_MARK is not set ++ ++# ++# Xtables targets ++# ++# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set ++# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set ++# CONFIG_NETFILTER_XT_TARGET_DSCP is not set ++CONFIG_NETFILTER_XT_TARGET_HL=m ++# CONFIG_NETFILTER_XT_TARGET_HMARK is not set ++# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set ++# CONFIG_NETFILTER_XT_TARGET_LED is not set ++# CONFIG_NETFILTER_XT_TARGET_LOG is not set ++# CONFIG_NETFILTER_XT_TARGET_MARK is not set ++# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set ++# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set ++# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set ++# CONFIG_NETFILTER_XT_TARGET_TEE is not set ++# CONFIG_NETFILTER_XT_TARGET_TRACE is not set ++# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set ++# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set ++ ++# ++# Xtables matches ++# ++# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set ++# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set ++# CONFIG_NETFILTER_XT_MATCH_CPU is not set ++# CONFIG_NETFILTER_XT_MATCH_DCCP is not set ++# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set ++# CONFIG_NETFILTER_XT_MATCH_DSCP is not set ++CONFIG_NETFILTER_XT_MATCH_ECN=m ++# CONFIG_NETFILTER_XT_MATCH_ESP is not set ++# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set ++CONFIG_NETFILTER_XT_MATCH_HL=m ++# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set ++# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set ++# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set ++# CONFIG_NETFILTER_XT_MATCH_MAC is not set ++# CONFIG_NETFILTER_XT_MATCH_MARK is not set ++# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set ++# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set ++# CONFIG_NETFILTER_XT_MATCH_OWNER is not set ++# CONFIG_NETFILTER_XT_MATCH_POLICY is not set ++# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set ++# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set ++# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set ++# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set ++# CONFIG_NETFILTER_XT_MATCH_REALM is not set ++# CONFIG_NETFILTER_XT_MATCH_RECENT is not set ++# CONFIG_NETFILTER_XT_MATCH_SCTP is not set ++# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set ++# CONFIG_NETFILTER_XT_MATCH_STRING is not set ++# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set ++# CONFIG_NETFILTER_XT_MATCH_TIME is not set ++# CONFIG_NETFILTER_XT_MATCH_U32 is not set ++CONFIG_IP_VS=m ++# CONFIG_IP_VS_IPV6 is not set ++# CONFIG_IP_VS_DEBUG is not set ++CONFIG_IP_VS_TAB_BITS=12 ++ ++# ++# IPVS transport protocol load balancing support ++# ++# CONFIG_IP_VS_PROTO_TCP is not set ++# CONFIG_IP_VS_PROTO_UDP is not set ++# CONFIG_IP_VS_PROTO_AH_ESP is not set ++# CONFIG_IP_VS_PROTO_ESP is not set ++# CONFIG_IP_VS_PROTO_AH is not set ++# CONFIG_IP_VS_PROTO_SCTP is not set ++ ++# ++# IPVS scheduler ++# ++# CONFIG_IP_VS_RR is not set ++# CONFIG_IP_VS_WRR is not set ++# CONFIG_IP_VS_LC is not set ++# CONFIG_IP_VS_WLC is not set ++# CONFIG_IP_VS_LBLC is not set ++# CONFIG_IP_VS_LBLCR is not set ++# CONFIG_IP_VS_DH is not set ++# CONFIG_IP_VS_SH is not set ++# CONFIG_IP_VS_SED is not set ++# CONFIG_IP_VS_NQ is not set ++ ++# ++# IPVS SH scheduler ++# ++CONFIG_IP_VS_SH_TAB_BITS=8 ++ ++# ++# IPVS application helper ++# ++ ++# ++# IP: Netfilter Configuration ++# ++# CONFIG_NF_DEFRAG_IPV4 is not set ++CONFIG_IP_NF_QUEUE=m ++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_ULOG=m ++CONFIG_IP_NF_MANGLE=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 is not set ++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_MANGLE=m ++CONFIG_IP6_NF_RAW=m ++CONFIG_IP6_NF_SECURITY=m ++# CONFIG_BRIDGE_NF_EBTABLES is not set ++# 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 is not set ++CONFIG_STP=m ++CONFIG_GARP=m ++CONFIG_BRIDGE=m ++CONFIG_BRIDGE_IGMP_SNOOPING=y ++CONFIG_NET_DSA=m ++# CONFIG_NET_DSA_TAG_DSA is not set ++# CONFIG_NET_DSA_TAG_EDSA is not set ++# CONFIG_NET_DSA_TAG_TRAILER is not set ++CONFIG_VLAN_8021Q=m ++CONFIG_VLAN_8021Q_GVRP=y ++# CONFIG_DECNET is not set ++CONFIG_LLC=m ++# 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_WAN_ROUTER is not set ++CONFIG_PHONET=m ++# CONFIG_IEEE802154 is not set ++CONFIG_NET_SCHED=y ++ ++# ++# Queueing/Scheduling ++# ++# CONFIG_NET_SCH_CBQ is not set ++# CONFIG_NET_SCH_HTB is not set ++# CONFIG_NET_SCH_HFSC is not set ++# CONFIG_NET_SCH_PRIO is not set ++# CONFIG_NET_SCH_MULTIQ is not set ++# CONFIG_NET_SCH_RED is not set ++# CONFIG_NET_SCH_SFB is not set ++# CONFIG_NET_SCH_SFQ is not set ++# CONFIG_NET_SCH_TEQL is not set ++# CONFIG_NET_SCH_TBF is not set ++# CONFIG_NET_SCH_GRED is not set ++# CONFIG_NET_SCH_DSMARK is not set ++# CONFIG_NET_SCH_NETEM is not set ++# CONFIG_NET_SCH_DRR is not set ++# CONFIG_NET_SCH_MQPRIO is not set ++# CONFIG_NET_SCH_CHOKE is not set ++# CONFIG_NET_SCH_QFQ is not set ++CONFIG_NET_SCH_CODEL=y ++CONFIG_NET_SCH_FQ_CODEL=y ++# CONFIG_NET_SCH_PLUG is not set ++ ++# ++# Classification ++# ++CONFIG_NET_CLS=y ++# CONFIG_NET_CLS_BASIC is not set ++# CONFIG_NET_CLS_TCINDEX is not set ++# CONFIG_NET_CLS_ROUTE4 is not set ++# CONFIG_NET_CLS_FW is not set ++# CONFIG_NET_CLS_U32 is not set ++# CONFIG_NET_CLS_RSVP is not set ++# CONFIG_NET_CLS_RSVP6 is not set ++# CONFIG_NET_CLS_FLOW is not set ++CONFIG_NET_CLS_CGROUP=m ++# CONFIG_NET_EMATCH is not set ++# CONFIG_NET_CLS_ACT is not set ++CONFIG_NET_SCH_FIFO=y ++# CONFIG_DCB is not set ++CONFIG_DNS_RESOLVER=y ++CONFIG_BATMAN_ADV=m ++CONFIG_BATMAN_ADV_BLA=y ++# CONFIG_BATMAN_ADV_DEBUG is not set ++CONFIG_OPENVSWITCH=m ++CONFIG_RPS=y ++CONFIG_RFS_ACCEL=y ++CONFIG_XPS=y ++CONFIG_NETPRIO_CGROUP=m ++CONFIG_BQL=y ++CONFIG_BPF_JIT=y ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++# CONFIG_NET_TCPPROBE is not set ++# CONFIG_NET_DROP_MONITOR 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 is not set ++# CONFIG_CAN_SLCAN is not set ++CONFIG_CAN_DEV=m ++CONFIG_CAN_CALC_BITTIMING=y ++CONFIG_CAN_TI_HECC=m ++CONFIG_CAN_MCP251X=m ++# CONFIG_CAN_SJA1000 is not set ++CONFIG_CAN_C_CAN=m ++CONFIG_CAN_C_CAN_PLATFORM=m ++# CONFIG_CAN_CC770 is not set ++ ++# ++# CAN USB interfaces ++# ++CONFIG_CAN_EMS_USB=m ++CONFIG_CAN_ESD_USB2=m ++CONFIG_CAN_PEAK_USB=m ++# CONFIG_CAN_SOFTING is not set ++# CONFIG_CAN_DEBUG_DEVICES is not set ++CONFIG_IRDA=m ++ ++# ++# IrDA protocols ++# ++CONFIG_IRLAN=m ++# CONFIG_IRNET is not set ++CONFIG_IRCOMM=m ++CONFIG_IRDA_ULTRA=y ++ ++# ++# IrDA options ++# ++CONFIG_IRDA_CACHE_LAST_LSAP=y ++CONFIG_IRDA_FAST_RR=y ++# CONFIG_IRDA_DEBUG is not set ++ ++# ++# Infrared-port device drivers ++# ++ ++# ++# SIR device drivers ++# ++CONFIG_IRTTY_SIR=m ++ ++# ++# Dongle support ++# ++CONFIG_DONGLE=y ++CONFIG_ESI_DONGLE=m ++CONFIG_ACTISYS_DONGLE=m ++CONFIG_TEKRAM_DONGLE=m ++CONFIG_TOIM3232_DONGLE=m ++CONFIG_LITELINK_DONGLE=m ++CONFIG_MA600_DONGLE=m ++CONFIG_GIRBIL_DONGLE=m ++CONFIG_MCP2120_DONGLE=m ++CONFIG_OLD_BELKIN_DONGLE=m ++CONFIG_ACT200L_DONGLE=m ++CONFIG_KINGSUN_DONGLE=m ++CONFIG_KSDAZZLE_DONGLE=m ++CONFIG_KS959_DONGLE=m ++ ++# ++# FIR device drivers ++# ++CONFIG_USB_IRDA=m ++# CONFIG_SIGMATEL_FIR is not set ++CONFIG_MCS_FIR=m ++CONFIG_BT=m ++CONFIG_BT_RFCOMM=m ++CONFIG_BT_RFCOMM_TTY=y ++CONFIG_BT_BNEP=m ++CONFIG_BT_BNEP_MC_FILTER=y ++CONFIG_BT_BNEP_PROTO_FILTER=y ++CONFIG_BT_HIDP=m ++ ++# ++# Bluetooth device drivers ++# ++CONFIG_BT_HCIBTUSB=m ++CONFIG_BT_HCIBTSDIO=m ++CONFIG_BT_HCIUART=m ++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 is not set ++# CONFIG_BT_MRVL is not set ++CONFIG_BT_ATH3K=m ++# CONFIG_BT_WILINK is not set ++CONFIG_AF_RXRPC=m ++# CONFIG_AF_RXRPC_DEBUG is not set ++# CONFIG_RXKAD 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_CFG80211=m ++# CONFIG_NL80211_TESTMODE is not set ++# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set ++# CONFIG_CFG80211_REG_DEBUG is not set ++# CONFIG_CFG80211_CERTIFICATION_ONUS is not set ++CONFIG_CFG80211_DEFAULT_PS=y ++CONFIG_CFG80211_DEBUGFS=y ++# CONFIG_CFG80211_INTERNAL_REGDB is not set ++CONFIG_CFG80211_WEXT=y ++CONFIG_LIB80211=m ++# CONFIG_LIB80211_DEBUG is not set ++CONFIG_MAC80211=m ++CONFIG_MAC80211_HAS_RC=y ++CONFIG_MAC80211_RC_PID=y ++CONFIG_MAC80211_RC_MINSTREL=y ++CONFIG_MAC80211_RC_MINSTREL_HT=y ++CONFIG_MAC80211_RC_DEFAULT_PID=y ++# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set ++CONFIG_MAC80211_RC_DEFAULT="pid" ++CONFIG_MAC80211_MESH=y ++CONFIG_MAC80211_LEDS=y ++CONFIG_MAC80211_DEBUGFS=y ++# CONFIG_MAC80211_MESSAGE_TRACING is not set ++# CONFIG_MAC80211_DEBUG_MENU is not set ++CONFIG_WIMAX=m ++CONFIG_WIMAX_DEBUG_LEVEL=8 ++CONFIG_RFKILL=m ++CONFIG_RFKILL_LEDS=y ++CONFIG_RFKILL_INPUT=y ++CONFIG_RFKILL_REGULATOR=m ++CONFIG_RFKILL_GPIO=m ++CONFIG_NET_9P=m ++CONFIG_NET_9P_VIRTIO=m ++# CONFIG_NET_9P_DEBUG is not set ++# CONFIG_CAIF is not set ++CONFIG_CEPH_LIB=m ++# CONFIG_CEPH_LIB_PRETTYDEBUG is not set ++# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set ++CONFIG_NFC=m ++CONFIG_NFC_NCI=m ++CONFIG_NFC_HCI=m ++CONFIG_NFC_SHDLC=y ++# CONFIG_NFC_LLCP is not set ++ ++# ++# Near Field Communication (NFC) devices ++# ++CONFIG_PN544_HCI_NFC=m ++CONFIG_NFC_PN533=m ++# CONFIG_NFC_WILINK is not set ++CONFIG_HAVE_BPF_JIT=y ++ ++# ++# Device Drivers ++# ++ ++# ++# 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_DEBUG_DRIVER 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=m ++CONFIG_REGMAP_MMIO=y ++# CONFIG_DMA_SHARED_BUFFER is not set ++# CONFIG_CMA is not set ++ ++# ++# Bus devices ++# ++CONFIG_OMAP_OCP2SCP=y ++CONFIG_OMAP_INTERCONNECT=y ++CONFIG_CONNECTOR=y ++CONFIG_PROC_EVENTS=y ++CONFIG_MTD=y ++# CONFIG_MTD_TESTS is not set ++# CONFIG_MTD_REDBOOT_PARTS is not set ++CONFIG_MTD_CMDLINE_PARTS=y ++# 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_CHAR=y ++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=y ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_GEN_PROBE=y ++# CONFIG_MTD_CFI_ADV_OPTIONS 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_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_CFI_STAA is not set ++CONFIG_MTD_CFI_UTIL=y ++# 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_PHYSMAP is not set ++# CONFIG_MTD_PHYSMAP_OF 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_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOC2001PLUS is not set ++# CONFIG_MTD_DOCG3 is not set ++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_MUSEUM_IDS is not set ++# CONFIG_MTD_NAND_GPIO is not set ++CONFIG_MTD_NAND_OMAP2=y ++# CONFIG_MTD_NAND_OMAP_BCH is not set ++CONFIG_MTD_NAND_IDS=y ++# 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=y ++CONFIG_MTD_ONENAND_VERIFY_WRITE=y ++# CONFIG_MTD_ONENAND_GENERIC is not set ++CONFIG_MTD_ONENAND_OMAP2=y ++# CONFIG_MTD_ONENAND_OTP is not set ++# CONFIG_MTD_ONENAND_2X_PROGRAM is not set ++# CONFIG_MTD_ONENAND_SIM is not set ++ ++# ++# LPDDR flash memory drivers ++# ++# CONFIG_MTD_LPDDR is not set ++CONFIG_MTD_UBI=y ++CONFIG_MTD_UBI_WL_THRESHOLD=4096 ++CONFIG_MTD_UBI_BEB_LIMIT=20 ++CONFIG_MTD_UBI_FASTMAP=y ++# CONFIG_MTD_UBI_GLUEBI is not set ++CONFIG_DTC=y ++CONFIG_OF=y ++ ++# ++# Device Tree and Open Firmware support ++# ++CONFIG_PROC_DEVICETREE=y ++# CONFIG_OF_SELFTEST is not set ++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 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 is not set ++# CONFIG_BLK_DEV_NBD is not set ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_COUNT=16 ++CONFIG_BLK_DEV_RAM_SIZE=16384 ++# CONFIG_BLK_DEV_XIP is not set ++# CONFIG_CDROM_PKTCDVD is not set ++# CONFIG_ATA_OVER_ETH is not set ++# CONFIG_MG_DISK is not set ++CONFIG_VIRTIO_BLK=m ++# 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_ICS932S401 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=m ++# 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_BMP085=y ++CONFIG_BMP085_I2C=m ++# CONFIG_BMP085_SPI is not set ++# CONFIG_USB_SWITCH_FSA9480 is not set ++# CONFIG_GPEVT is not set ++# CONFIG_C2PORT is not set ++ ++# ++# EEPROM support ++# ++CONFIG_EEPROM_AT24=y ++# CONFIG_EEPROM_AT25 is not set ++# CONFIG_EEPROM_LEGACY is not set ++# CONFIG_EEPROM_MAX6875 is not set ++CONFIG_EEPROM_93CX6=y ++# CONFIG_EEPROM_93XX46 is not set ++ ++# ++# Texas Instruments shared transport line discipline ++# ++CONFIG_TI_ST=m ++# 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 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=y ++ ++# ++# SCSI Transports ++# ++# CONFIG_SCSI_SPI_ATTRS is not set ++# CONFIG_SCSI_FC_ATTRS is not set ++# CONFIG_SCSI_ISCSI_ATTRS is not set ++# 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 is not set ++# CONFIG_ISCSI_BOOT_SYSFS is not set ++# CONFIG_LIBFC is not set ++# CONFIG_LIBFCOE is not set ++# CONFIG_SCSI_DEBUG is not set ++CONFIG_SCSI_VIRTIO=m ++# 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 is not set ++# CONFIG_BLK_DEV_DM is not set ++# CONFIG_TARGET_CORE is not set ++CONFIG_NETDEVICES=y ++CONFIG_NET_CORE=y ++# CONFIG_BONDING is not set ++# CONFIG_DUMMY is not set ++# CONFIG_EQUALIZER is not set ++CONFIG_MII=y ++# CONFIG_NET_TEAM is not set ++# CONFIG_MACVLAN is not set ++CONFIG_VXLAN=m ++# CONFIG_NETCONSOLE is not set ++# CONFIG_NETPOLL is not set ++# CONFIG_NET_POLL_CONTROLLER is not set ++CONFIG_TUN=m ++# CONFIG_VETH is not set ++CONFIG_VIRTIO_NET=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_VENDOR_BROADCOM=y ++# CONFIG_B44 is not set ++# CONFIG_NET_CALXEDA_XGMAC is not set ++CONFIG_NET_VENDOR_CHELSIO=y ++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_NET_VENDOR_MICREL=y ++CONFIG_KS8842=m ++CONFIG_KS8851=y ++CONFIG_KS8851_MLL=y ++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_SEEQ8005 is not set ++CONFIG_NET_VENDOR_SMSC=y ++CONFIG_SMC91X=y ++# CONFIG_SMC911X is not set ++CONFIG_SMSC911X=y ++# CONFIG_SMSC911X_ARCH_HOOKS is not set ++CONFIG_NET_VENDOR_STMICRO=y ++# CONFIG_STMMAC_ETH is not set ++CONFIG_NET_VENDOR_TI=y ++CONFIG_TI_DAVINCI_EMAC=y ++CONFIG_TI_DAVINCI_MDIO=y ++CONFIG_TI_DAVINCI_CPDMA=y ++CONFIG_TI_CPSW=y ++CONFIG_NET_VENDOR_WIZNET=y ++# CONFIG_WIZNET_W5100 is not set ++# CONFIG_WIZNET_W5300 is not set ++CONFIG_PHYLIB=y ++ ++# ++# MII PHY device drivers ++# ++# CONFIG_AMD_PHY is not set ++# CONFIG_MARVELL_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=y ++# 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=m ++# CONFIG_MDIO_BUS_MUX_GPIO is not set ++CONFIG_MDIO_BUS_MUX_MMIOREG=m ++# CONFIG_MICREL_KS8995MA is not set ++CONFIG_PPP=m ++CONFIG_PPP_BSDCOMP=m ++CONFIG_PPP_DEFLATE=m ++CONFIG_PPP_FILTER=y ++CONFIG_PPP_MPPE=m ++CONFIG_PPP_MULTILINK=y ++CONFIG_PPPOE=m ++CONFIG_PPTP=m ++CONFIG_PPPOL2TP=m ++CONFIG_PPP_ASYNC=m ++# CONFIG_PPP_SYNC_TTY is not set ++# CONFIG_SLIP is not set ++CONFIG_SLHC=m ++ ++# ++# USB Network Adapters ++# ++# CONFIG_USB_CATC is not set ++# CONFIG_USB_KAWETH is not set ++# CONFIG_USB_PEGASUS is not set ++# CONFIG_USB_RTL8150 is not set ++CONFIG_USB_USBNET=y ++CONFIG_USB_NET_AX8817X=y ++CONFIG_USB_NET_CDCETHER=y ++# CONFIG_USB_NET_CDC_EEM is not set ++CONFIG_USB_NET_CDC_NCM=y ++# CONFIG_USB_NET_DM9601 is not set ++# CONFIG_USB_NET_SMSC75XX is not set ++CONFIG_USB_NET_SMSC95XX=y ++# CONFIG_USB_NET_GL620A is not set ++CONFIG_USB_NET_NET1080=y ++# CONFIG_USB_NET_PLUSB is not set ++# CONFIG_USB_NET_MCS7830 is not set ++# CONFIG_USB_NET_RNDIS_HOST is not set ++CONFIG_USB_NET_CDC_SUBSET=y ++CONFIG_USB_ALI_M5632=y ++CONFIG_USB_AN2720=y ++CONFIG_USB_BELKIN=y ++CONFIG_USB_ARMLINUX=y ++CONFIG_USB_EPSON2888=y ++CONFIG_USB_KC2190=y ++CONFIG_USB_NET_ZAURUS=y ++# CONFIG_USB_NET_CX82310_ETH is not set ++# CONFIG_USB_NET_KALMIA is not set ++# CONFIG_USB_NET_QMI_WWAN is not set ++# CONFIG_USB_HSO is not set ++# CONFIG_USB_NET_INT51X1 is not set ++# CONFIG_USB_CDC_PHONET is not set ++# CONFIG_USB_IPHETH is not set ++# CONFIG_USB_SIERRA_NET is not set ++# CONFIG_USB_VL600 is not set ++CONFIG_WLAN=y ++# CONFIG_LIBERTAS_THINFIRM is not set ++# CONFIG_AT76C50X_USB is not set ++# CONFIG_USB_ZD1201 is not set ++# CONFIG_USB_NET_RNDIS_WLAN is not set ++# CONFIG_RTL8187 is not set ++# CONFIG_MAC80211_HWSIM is not set ++# CONFIG_ATH_COMMON is not set ++# CONFIG_B43 is not set ++# CONFIG_B43LEGACY is not set ++# CONFIG_BRCMFMAC is not set ++# CONFIG_HOSTAP is not set ++CONFIG_LIBERTAS=m ++CONFIG_LIBERTAS_USB=m ++CONFIG_LIBERTAS_SDIO=m ++# CONFIG_LIBERTAS_SPI is not set ++CONFIG_LIBERTAS_DEBUG=y ++# CONFIG_LIBERTAS_MESH is not set ++# CONFIG_P54_COMMON is not set ++# CONFIG_RT2X00 is not set ++# CONFIG_RTL8192CU is not set ++# CONFIG_WL_TI is not set ++# CONFIG_ZD1211RW is not set ++# CONFIG_MWIFIEX is not set ++ ++# ++# WiMAX Wireless Broadband devices ++# ++# CONFIG_WIMAX_I2400M_USB is not set ++# CONFIG_WAN is not set ++# CONFIG_ISDN is not set ++ ++# ++# Input device support ++# ++CONFIG_INPUT=y ++# CONFIG_INPUT_FF_MEMLESS is not set ++# CONFIG_INPUT_POLLDEV is not set ++# CONFIG_INPUT_SPARSEKMAP is not set ++CONFIG_INPUT_MATRIXKMAP=y ++ ++# ++# 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=y ++CONFIG_INPUT_EVDEV=y ++# CONFIG_INPUT_EVBUG 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=y ++# 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_OMAP4 is not set ++CONFIG_KEYBOARD_TWL4030=y ++# 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_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_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 is not set ++# CONFIG_INPUT_TABLET is not set ++CONFIG_INPUT_TOUCHSCREEN=y ++CONFIG_TOUCHSCREEN_ADS7846=y ++# 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=m ++# 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=m ++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set ++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set ++CONFIG_TOUCHSCREEN_TI_AM335X_TSC=y ++# CONFIG_TOUCHSCREEN_PIXCIR is not set ++CONFIG_TOUCHSCREEN_WM97XX=m ++CONFIG_TOUCHSCREEN_WM9705=y ++CONFIG_TOUCHSCREEN_WM9712=y ++CONFIG_TOUCHSCREEN_WM9713=y ++# 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_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 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_TWL4030_PWRBUTTON=y ++# CONFIG_INPUT_TWL4030_VIBRA is not set ++# CONFIG_INPUT_UINPUT is not set ++# CONFIG_INPUT_PCF8574 is not set ++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set ++# CONFIG_INPUT_ADXL34X is not set ++# CONFIG_INPUT_CMA3000 is not set ++ ++# ++# Hardware I/O ports ++# ++CONFIG_SERIO=y ++CONFIG_SERIO_SERPORT=y ++CONFIG_SERIO_LIBPS2=y ++# CONFIG_SERIO_RAW is not set ++# CONFIG_SERIO_ALTERA_PS2 is not set ++# CONFIG_SERIO_PS2MULT is not set ++# CONFIG_GAMEPORT is not set ++ ++# ++# Character devices ++# ++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=y ++CONFIG_UNIX98_PTYS=y ++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set ++# CONFIG_LEGACY_PTYS is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++# CONFIG_N_GSM is not set ++# CONFIG_TRACE_SINK is not set ++CONFIG_DEVKMEM=y ++ ++# ++# Serial drivers ++# ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_8250_NR_UARTS=32 ++CONFIG_SERIAL_8250_RUNTIME_UARTS=4 ++CONFIG_SERIAL_8250_EXTENDED=y ++CONFIG_SERIAL_8250_MANY_PORTS=y ++CONFIG_SERIAL_8250_SHARE_IRQ=y ++CONFIG_SERIAL_8250_DETECT_IRQ=y ++CONFIG_SERIAL_8250_RSA=y ++# CONFIG_SERIAL_8250_DW is not set ++# CONFIG_SERIAL_8250_EM 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_OF_PLATFORM is not set ++CONFIG_SERIAL_OMAP=y ++CONFIG_SERIAL_OMAP_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_TTY_PRINTK is not set ++CONFIG_HVC_DRIVER=y ++# CONFIG_HVC_DCC is not set ++CONFIG_VIRTIO_CONSOLE=m ++# 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_VIRTIO=m ++# 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_I2C=y ++CONFIG_I2C_BOARDINFO=y ++CONFIG_I2C_COMPAT=y ++CONFIG_I2C_CHARDEV=y ++# CONFIG_I2C_MUX is not set ++CONFIG_I2C_HELPER_AUTO=y ++CONFIG_I2C_ALGOBIT=m ++ ++# ++# I2C Hardware Bus support ++# ++ ++# ++# I2C system bus drivers (mostly embedded / system-on-chip) ++# ++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set ++# CONFIG_I2C_GPIO is not set ++# CONFIG_I2C_OCORES is not set ++CONFIG_I2C_OMAP=y ++# 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_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_GPIO is not set ++# CONFIG_SPI_OC_TINY is not set ++CONFIG_SPI_OMAP24XX=y ++# CONFIG_SPI_PXA2XX_PCI is not set ++CONFIG_SPI_SC18IS602=m ++CONFIG_SPI_XCOMM=m ++# CONFIG_SPI_XILINX is not set ++# CONFIG_SPI_DESIGNWARE is not set ++ ++# ++# SPI Protocol Masters ++# ++CONFIG_SPI_SPIDEV=y ++# CONFIG_SPI_TLE62X0 is not set ++# CONFIG_HSI is not set ++ ++# ++# PPS support ++# ++# CONFIG_PPS is not set ++ ++# ++# PPS generators support ++# ++ ++# ++# PTP clock support ++# ++ ++# ++# Enable Device Drivers -> PPS to see the PTP clock options. ++# ++CONFIG_PINCTRL=y ++ ++# ++# Pin controllers ++# ++CONFIG_PINMUX=y ++CONFIG_PINCONF=y ++# CONFIG_DEBUG_PINCTRL is not set ++CONFIG_PINCTRL_SINGLE=y ++# CONFIG_PINCTRL_SAMSUNG is not set ++# CONFIG_PINCTRL_EXYNOS4 is not set ++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y ++CONFIG_ARCH_REQUIRE_GPIOLIB=y ++CONFIG_GPIOLIB=y ++CONFIG_OF_GPIO=y ++CONFIG_DEBUG_GPIO=y ++CONFIG_GPIO_SYSFS=y ++ ++# ++# Memory mapped GPIO drivers: ++# ++# CONFIG_GPIO_GENERIC_PLATFORM is not set ++# CONFIG_GPIO_EM 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_TWL4030=y ++# 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: ++# ++CONFIG_W1=y ++CONFIG_W1_CON=y ++ ++# ++# 1-wire Bus Masters ++# ++CONFIG_W1_MASTER_DS2490=m ++CONFIG_W1_MASTER_DS2482=m ++CONFIG_W1_MASTER_DS1WM=m ++CONFIG_W1_MASTER_GPIO=y ++CONFIG_HDQ_MASTER_OMAP=m ++ ++# ++# 1-wire Slaves ++# ++CONFIG_W1_SLAVE_THERM=y ++CONFIG_W1_SLAVE_SMEM=y ++CONFIG_W1_SLAVE_DS2408=m ++CONFIG_W1_SLAVE_DS2423=m ++CONFIG_W1_SLAVE_DS2431=m ++CONFIG_W1_SLAVE_DS2433=m ++CONFIG_W1_SLAVE_DS2433_CRC=y ++CONFIG_W1_SLAVE_DS2760=m ++CONFIG_W1_SLAVE_DS2780=m ++CONFIG_W1_SLAVE_DS2781=m ++CONFIG_W1_SLAVE_DS28E04=m ++CONFIG_W1_SLAVE_BQ27000=m ++CONFIG_POWER_SUPPLY=y ++# CONFIG_POWER_SUPPLY_DEBUG is not set ++# CONFIG_PDA_POWER is not set ++CONFIG_GENERIC_ADC_BATTERY=m ++# CONFIG_TEST_POWER is not set ++# CONFIG_BATTERY_DS2760 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_CHARGER_ISP1704 is not set ++# CONFIG_CHARGER_MAX8903 is not set ++# CONFIG_CHARGER_TWL4030 is not set ++# CONFIG_CHARGER_LP8727 is not set ++CONFIG_CHARGER_GPIO=m ++# CONFIG_CHARGER_MANAGER is not set ++# CONFIG_CHARGER_SMB347 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_ADT7410=m ++# 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=m ++CONFIG_SENSORS_HIH6130=m ++# 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_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=m ++# CONFIG_SENSORS_MAX6639 is not set ++# CONFIG_SENSORS_MAX6642 is not set ++# CONFIG_SENSORS_MAX6650 is not set ++# CONFIG_SENSORS_MCP3021 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=m ++# 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_INA2XX is not set ++# CONFIG_SENSORS_THMC50 is not set ++CONFIG_SENSORS_TMP102=m ++# 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_CPU_THERMAL=y ++CONFIG_WATCHDOG=y ++# CONFIG_WATCHDOG_CORE is not set ++# CONFIG_WATCHDOG_NOWAYOUT is not set ++ ++# ++# Watchdog Device Drivers ++# ++# CONFIG_SOFT_WATCHDOG is not set ++# CONFIG_DW_WATCHDOG is not set ++# CONFIG_MPCORE_WATCHDOG is not set ++CONFIG_OMAP_WATCHDOG=y ++CONFIG_TWL4030_WATCHDOG=y ++# 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=y ++# CONFIG_MFD_88PM860X is not set ++# CONFIG_MFD_88PM800 is not set ++# CONFIG_MFD_88PM805 is not set ++# CONFIG_MFD_SM501 is not set ++# CONFIG_MFD_ASIC3 is not set ++CONFIG_MFD_TI_AM335X_TSCADC=y ++# CONFIG_HTC_EGPIO is not set ++# CONFIG_HTC_PASIC3 is not set ++# CONFIG_HTC_I2CPLD is not set ++# CONFIG_UCB1400_CORE is not set ++# CONFIG_MFD_LM3533 is not set ++# CONFIG_TPS6105X is not set ++# CONFIG_TPS65010 is not set ++# CONFIG_TPS6507X is not set ++CONFIG_MFD_TPS65217=y ++# CONFIG_MFD_TPS6586X is not set ++# CONFIG_MFD_TPS65910 is not set ++# CONFIG_MFD_TPS65912_I2C is not set ++# CONFIG_MFD_TPS65912_SPI is not set ++CONFIG_TWL4030_CORE=y ++# CONFIG_TWL4030_MADC is not set ++CONFIG_TWL4030_POWER=y ++# CONFIG_MFD_TWL4030_AUDIO is not set ++# CONFIG_TWL6040_CORE is not set ++# CONFIG_MFD_STMPE is not set ++# CONFIG_MFD_TC3589X is not set ++# CONFIG_MFD_TMIO is not set ++# CONFIG_MFD_T7L66XB is not set ++# CONFIG_MFD_SMSC is not set ++# CONFIG_MFD_TC6387XB is not set ++# CONFIG_MFD_TC6393XB 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_PMIC_ADP5520 is not set ++# CONFIG_MFD_LP8788 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_MFD_SEC_CORE 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_MFD_PCF50633 is not set ++# CONFIG_MFD_MC13XXX_SPI is not set ++# CONFIG_MFD_MC13XXX_I2C is not set ++# CONFIG_ABX500_CORE is not set ++# CONFIG_EZX_PCAP is not set ++CONFIG_MFD_WL1273_CORE=m ++# CONFIG_MFD_TPS65090 is not set ++# CONFIG_MFD_AAT2870_CORE is not set ++# CONFIG_MFD_RC5T583 is not set ++# CONFIG_MFD_SYSCON is not set ++# CONFIG_MFD_PALMAS is not set ++CONFIG_REGULATOR=y ++# CONFIG_REGULATOR_DEBUG is not set ++# CONFIG_REGULATOR_DUMMY is not set ++CONFIG_REGULATOR_FIXED_VOLTAGE=y ++# 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_LP3971 is not set ++# CONFIG_REGULATOR_LP3972 is not set ++# CONFIG_REGULATOR_LP872X is not set ++# CONFIG_REGULATOR_TPS62360 is not set ++CONFIG_REGULATOR_TPS65023=y ++CONFIG_REGULATOR_TPS6507X=y ++CONFIG_REGULATOR_TPS65217=y ++# CONFIG_REGULATOR_TPS6524X is not set ++CONFIG_REGULATOR_TWL4030=y ++CONFIG_MEDIA_SUPPORT=m ++ ++# ++# Multimedia core support ++# ++CONFIG_MEDIA_CAMERA_SUPPORT=y ++CONFIG_MEDIA_ANALOG_TV_SUPPORT=y ++CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y ++CONFIG_MEDIA_RADIO_SUPPORT=y ++CONFIG_MEDIA_RC_SUPPORT=y ++CONFIG_MEDIA_CONTROLLER=y ++CONFIG_VIDEO_DEV=m ++CONFIG_VIDEO_V4L2_SUBDEV_API=y ++CONFIG_VIDEO_V4L2=m ++# CONFIG_VIDEO_ADV_DEBUG is not set ++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set ++CONFIG_VIDEO_TUNER=m ++CONFIG_V4L2_MEM2MEM_DEV=m ++CONFIG_VIDEOBUF_GEN=m ++CONFIG_VIDEOBUF_VMALLOC=m ++CONFIG_VIDEOBUF_DMA_CONTIG=m ++CONFIG_VIDEOBUF_DVB=m ++CONFIG_VIDEOBUF2_CORE=m ++CONFIG_VIDEOBUF2_MEMOPS=m ++CONFIG_VIDEOBUF2_DMA_CONTIG=m ++CONFIG_VIDEOBUF2_VMALLOC=m ++CONFIG_DVB_CORE=m ++CONFIG_DVB_NET=y ++CONFIG_DVB_MAX_ADAPTERS=8 ++CONFIG_DVB_DYNAMIC_MINORS=y ++ ++# ++# Media drivers ++# ++CONFIG_RC_CORE=m ++CONFIG_RC_MAP=m ++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_REDRAT3=m ++CONFIG_IR_STREAMZAP=m ++CONFIG_IR_IGUANA=m ++CONFIG_IR_TTUSBIR=m ++CONFIG_IR_RX51=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 is not set ++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_AU0828=m ++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_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_CYPRESS_FIRMWARE=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_SMS_USB_DRV is not set ++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_TTPCI_EEPROM=m ++CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_VPSS_SYSTEM=m ++CONFIG_VIDEO_VPFE_CAPTURE=m ++CONFIG_VIDEO_DM6446_CCDC=m ++CONFIG_VIDEO_OMAP2_VOUT_VRFB=y ++CONFIG_VIDEO_OMAP2_VOUT=m ++# CONFIG_VIDEO_TIMBERDALE is not set ++CONFIG_SOC_CAMERA=m ++CONFIG_SOC_CAMERA_PLATFORM=m ++# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set ++# CONFIG_VIDEO_SH_MOBILE_CEU is not set ++CONFIG_V4L_MEM2MEM_DRIVERS=y ++CONFIG_VIDEO_MEM2MEM_DEINTERLACE=m ++CONFIG_V4L_TEST_DRIVERS=y ++CONFIG_VIDEO_VIVI=m ++CONFIG_VIDEO_MEM2MEM_TESTDEV=m ++ ++# ++# Supported MMC/SDIO adapters ++# ++# CONFIG_SMS_SDIO_DRV is not set ++CONFIG_RADIO_ADAPTERS=y ++CONFIG_RADIO_SI470X=y ++CONFIG_USB_SI470X=m ++CONFIG_I2C_SI470X=m ++CONFIG_USB_MR800=m ++CONFIG_USB_DSBR=m ++# CONFIG_RADIO_SHARK is not set ++CONFIG_RADIO_SHARK2=m ++CONFIG_I2C_SI4713=m ++CONFIG_RADIO_SI4713=m ++CONFIG_USB_KEENE=m ++CONFIG_RADIO_TEA5764=m ++CONFIG_RADIO_SAA7706H=m ++CONFIG_RADIO_TEF6862=m ++CONFIG_RADIO_WL1273=m ++ ++# ++# Texas Instruments WL128x FM driver (ST based) ++# ++CONFIG_RADIO_WL128X=m ++CONFIG_DVB_B2C2_FLEXCOP=m ++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y ++ ++# ++# Media ancillary drivers (tuners, sensors, i2c, frontends) ++# ++CONFIG_VIDEO_TVEEPROM=m ++CONFIG_VIDEO_IR_I2C=m ++ ++# ++# 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 ++ ++# ++# MPEG video encoders ++# ++CONFIG_VIDEO_CX2341X=m ++ ++# ++# Video encoders ++# ++ ++# ++# Camera sensor devices ++# ++CONFIG_VIDEO_MT9V011=m ++ ++# ++# Flash devices ++# ++ ++# ++# Video improvement chips ++# ++ ++# ++# Miscelaneous helper chips ++# ++ ++# ++# Sensors used on soc_camera driver ++# ++ ++# ++# soc_camera sensor drivers ++# ++# CONFIG_SOC_CAMERA_IMX074 is not set ++CONFIG_SOC_CAMERA_MT9M001=m ++CONFIG_SOC_CAMERA_MT9M111=m ++CONFIG_SOC_CAMERA_MT9T031=m ++CONFIG_SOC_CAMERA_MT9T112=m ++CONFIG_SOC_CAMERA_MT9V022=m ++# CONFIG_SOC_CAMERA_OV2640 is not set ++# CONFIG_SOC_CAMERA_OV5642 is not set ++# CONFIG_SOC_CAMERA_OV6650 is not set ++# CONFIG_SOC_CAMERA_OV772X is not set ++# CONFIG_SOC_CAMERA_OV9640 is not set ++# CONFIG_SOC_CAMERA_OV9740 is not set ++# CONFIG_SOC_CAMERA_RJ54N1 is not set ++# CONFIG_SOC_CAMERA_TW9910 is not set ++CONFIG_MEDIA_ATTACH=y ++CONFIG_MEDIA_TUNER=m ++CONFIG_MEDIA_TUNER_SIMPLE=m ++CONFIG_MEDIA_TUNER_TDA8290=m ++CONFIG_MEDIA_TUNER_TDA827X=m ++CONFIG_MEDIA_TUNER_TDA18271=m ++CONFIG_MEDIA_TUNER_TDA9887=m ++CONFIG_MEDIA_TUNER_TEA5761=m ++CONFIG_MEDIA_TUNER_TEA5767=m ++CONFIG_MEDIA_TUNER_MT20XX=m ++CONFIG_MEDIA_TUNER_MT2060=m ++CONFIG_MEDIA_TUNER_MT2063=m ++CONFIG_MEDIA_TUNER_MT2266=m ++CONFIG_MEDIA_TUNER_QT1010=m ++CONFIG_MEDIA_TUNER_XC2028=m ++CONFIG_MEDIA_TUNER_XC5000=m ++CONFIG_MEDIA_TUNER_XC4000=m ++CONFIG_MEDIA_TUNER_MXL5005S=m ++CONFIG_MEDIA_TUNER_MXL5007T=m ++CONFIG_MEDIA_TUNER_MC44S803=m ++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_TUA9001=m ++ ++# ++# Multistandard (satellite) frontends ++# ++CONFIG_DVB_STB0899=m ++CONFIG_DVB_STB6100=m ++CONFIG_DVB_STV090x=m ++CONFIG_DVB_STV6110x=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_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 ++ ++# ++# 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_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 is not set ++# CONFIG_VGASTATE is not set ++# CONFIG_VIDEO_OUTPUT_CONTROL is not set ++CONFIG_FB=y ++CONFIG_FIRMWARE_EDID=y ++# 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=y ++CONFIG_FB_SYS_FILLRECT=y ++CONFIG_FB_SYS_COPYAREA=y ++CONFIG_FB_SYS_IMAGEBLIT=y ++CONFIG_FB_FOREIGN_ENDIAN=y ++CONFIG_FB_BOTH_ENDIAN=y ++# CONFIG_FB_BIG_ENDIAN is not set ++# CONFIG_FB_LITTLE_ENDIAN is not set ++CONFIG_FB_SYS_FOPS=y ++# CONFIG_FB_WMT_GE_ROPS is not set ++CONFIG_FB_DEFERRED_IO=y ++# CONFIG_FB_SVGALIB is not set ++# CONFIG_FB_MACMODES is not set ++# CONFIG_FB_BACKLIGHT is not set ++CONFIG_FB_MODE_HELPERS=y ++CONFIG_FB_TILEBLITTING=y ++ ++# ++# Frame buffer hardware drivers ++# ++# CONFIG_FB_UVESA is not set ++# CONFIG_FB_S1D13XXX is not set ++# CONFIG_FB_TMIO is not set ++# CONFIG_FB_SMSCUFX is not set ++# CONFIG_FB_UDL is not set ++CONFIG_FB_DA8XX=y ++# 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_ST7735=y ++CONFIG_OMAP2_VRAM=y ++CONFIG_OMAP2_VRFB=y ++CONFIG_OMAP2_DSS=m ++CONFIG_OMAP2_VRAM_SIZE=0 ++CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y ++# CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS is not set ++CONFIG_OMAP2_DSS_DPI=y ++CONFIG_OMAP2_DSS_RFBI=y ++CONFIG_OMAP2_DSS_VENC=y ++CONFIG_OMAP4_DSS_HDMI=y ++CONFIG_OMAP2_DSS_SDI=y ++CONFIG_OMAP2_DSS_DSI=y ++CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0 ++CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET=y ++CONFIG_FB_OMAP2=m ++CONFIG_FB_OMAP2_DEBUG_SUPPORT=y ++CONFIG_FB_OMAP2_NUM_FBS=3 ++ ++# ++# OMAP2/3 Display Device Drivers ++# ++CONFIG_PANEL_GENERIC_DPI=m ++# CONFIG_PANEL_TFP410 is not set ++# CONFIG_PANEL_LGPHILIPS_LB035Q02 is not set ++CONFIG_PANEL_SHARP_LS037V7DW01=m ++CONFIG_PANEL_NEC_NL8048HL11_01B=m ++# CONFIG_PANEL_PICODLP is not set ++CONFIG_PANEL_TAAL=m ++CONFIG_PANEL_TPO_TD043MTEA1=m ++CONFIG_PANEL_ACX565AKM=m ++# CONFIG_PANEL_N8X0 is not set ++# CONFIG_EXYNOS_VIDEO is not set ++CONFIG_BACKLIGHT_LCD_SUPPORT=y ++CONFIG_LCD_CLASS_DEVICE=y ++# CONFIG_LCD_L4F00242T03 is not set ++# CONFIG_LCD_LMS283GF05 is not set ++# CONFIG_LCD_LTV350QV is not set ++# CONFIG_LCD_TDO24M is not set ++# CONFIG_LCD_VGG2432A4 is not set ++CONFIG_LCD_PLATFORM=y ++# CONFIG_LCD_S6E63M0 is not set ++# CONFIG_LCD_LD9040 is not set ++# CONFIG_LCD_AMS369FG06 is not set ++CONFIG_BACKLIGHT_CLASS_DEVICE=y ++CONFIG_BACKLIGHT_GENERIC=m ++CONFIG_BACKLIGHT_PWM=y ++# CONFIG_BACKLIGHT_ADP8860 is not set ++# CONFIG_BACKLIGHT_ADP8870 is not set ++CONFIG_BACKLIGHT_LM3630=m ++CONFIG_BACKLIGHT_LM3639=m ++# CONFIG_BACKLIGHT_LP855X is not set ++# CONFIG_BACKLIGHT_PANDORA is not set ++CONFIG_BACKLIGHT_TPS65217=y ++ ++# ++# Console display driver support ++# ++CONFIG_DUMMY_CONSOLE=y ++CONFIG_FRAMEBUFFER_CONSOLE=y ++# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set ++CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y ++CONFIG_FONTS=y ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++# CONFIG_FONT_6x11 is not set ++# CONFIG_FONT_7x14 is not set ++# CONFIG_FONT_PEARL_8x8 is not set ++# CONFIG_FONT_ACORN_8x8 is not set ++CONFIG_FONT_MINI_4x6=y ++# 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_SOUND=m ++CONFIG_SOUND_OSS_CORE=y ++CONFIG_SOUND_OSS_CORE_PRECLAIM=y ++CONFIG_SND=m ++CONFIG_SND_TIMER=m ++CONFIG_SND_PCM=m ++CONFIG_SND_HWDEP=m ++CONFIG_SND_RAWMIDI=m ++CONFIG_SND_COMPRESS_OFFLOAD=m ++CONFIG_SND_JACK=y ++# CONFIG_SND_SEQUENCER 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_HRTIMER is not set ++# CONFIG_SND_DYNAMIC_MINORS is not set ++CONFIG_SND_SUPPORT_OLD_API=y ++CONFIG_SND_VERBOSE_PROCFS=y ++CONFIG_SND_VERBOSE_PRINTK=y ++CONFIG_SND_DEBUG=y ++# CONFIG_SND_DEBUG_VERBOSE is not set ++# CONFIG_SND_PCM_XRUN_DEBUG is not set ++CONFIG_SND_VMASTER=y ++# CONFIG_SND_RAWMIDI_SEQ is not set ++# 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 is not set ++# CONFIG_SND_MTPAV is not set ++# CONFIG_SND_SERIAL_U16550 is not set ++# CONFIG_SND_MPU401 is not set ++CONFIG_SND_AC97_POWER_SAVE=y ++CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 ++CONFIG_SND_ARM=y ++CONFIG_SND_SPI=y ++CONFIG_SND_USB=y ++CONFIG_SND_USB_AUDIO=m ++# CONFIG_SND_USB_UA101 is not set ++# CONFIG_SND_USB_CAIAQ is not set ++# CONFIG_SND_USB_6FIRE is not set ++CONFIG_SND_SOC=m ++# CONFIG_SND_DESIGNWARE_I2S is not set ++CONFIG_SND_SOC_I2C_AND_SPI=m ++# CONFIG_SND_SOC_ALL_CODECS is not set ++# 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 is not set ++CONFIG_UHID=m ++CONFIG_HID_GENERIC=y ++ ++# ++# Special HID drivers ++# ++# CONFIG_HID_A4TECH is not set ++# CONFIG_HID_ACRUX is not set ++# CONFIG_HID_APPLE is not set ++# CONFIG_HID_AUREAL is not set ++# CONFIG_HID_BELKIN is not set ++# CONFIG_HID_CHERRY is not set ++# CONFIG_HID_CHICONY is not set ++# CONFIG_HID_PRODIKEYS is not set ++# CONFIG_HID_CYPRESS is not set ++# CONFIG_HID_DRAGONRISE is not set ++# CONFIG_HID_EMS_FF is not set ++# CONFIG_HID_ELECOM is not set ++# CONFIG_HID_EZKEY is not set ++# CONFIG_HID_HOLTEK is not set ++# CONFIG_HID_KEYTOUCH is not set ++# CONFIG_HID_KYE is not set ++# CONFIG_HID_UCLOGIC is not set ++# CONFIG_HID_WALTOP is not set ++# CONFIG_HID_GYRATION is not set ++# CONFIG_HID_TWINHAN is not set ++# CONFIG_HID_KENSINGTON is not set ++# CONFIG_HID_LCPOWER is not set ++CONFIG_HID_LENOVO_TPKBD=m ++# CONFIG_HID_LOGITECH is not set ++# CONFIG_HID_MAGICMOUSE is not set ++# CONFIG_HID_MICROSOFT is not set ++# CONFIG_HID_MONTEREY is not set ++# CONFIG_HID_MULTITOUCH is not set ++# CONFIG_HID_NTRIG is not set ++# CONFIG_HID_ORTEK is not set ++# CONFIG_HID_PANTHERLORD is not set ++# CONFIG_HID_PETALYNX is not set ++# CONFIG_HID_PICOLCD is not set ++# CONFIG_HID_PRIMAX is not set ++CONFIG_HID_PS3REMOTE=m ++# CONFIG_HID_ROCCAT is not set ++# CONFIG_HID_SAITEK is not set ++# CONFIG_HID_SAMSUNG is not set ++# CONFIG_HID_SONY is not set ++# CONFIG_HID_SPEEDLINK is not set ++# CONFIG_HID_SUNPLUS is not set ++# CONFIG_HID_GREENASIA is not set ++# CONFIG_HID_SMARTJOYPLUS is not set ++# CONFIG_HID_TIVO is not set ++# CONFIG_HID_TOPSEED is not set ++# CONFIG_HID_THRUSTMASTER is not set ++# CONFIG_HID_WACOM is not set ++# CONFIG_HID_WIIMOTE is not set ++# CONFIG_HID_ZEROPLUS is not set ++# CONFIG_HID_ZYDACRON is not set ++CONFIG_HID_SENSOR_HUB=m ++ ++# ++# USB HID support ++# ++CONFIG_USB_HID=y ++# CONFIG_HID_PID is not set ++# CONFIG_USB_HIDDEV is not set ++CONFIG_USB_ARCH_HAS_OHCI=y ++CONFIG_USB_ARCH_HAS_EHCI=y ++# 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=y ++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y ++ ++# ++# Miscellaneous USB options ++# ++# CONFIG_USB_DYNAMIC_MINORS is not set ++CONFIG_USB_SUSPEND=y ++# CONFIG_USB_OTG is not set ++# CONFIG_USB_OTG_WHITELIST is not set ++# CONFIG_USB_OTG_BLACKLIST_HUB is not set ++# CONFIG_USB_DWC3 is not set ++CONFIG_USB_MON=y ++# CONFIG_USB_WUSB_CBAF is not set ++ ++# ++# USB Host Controller Drivers ++# ++# CONFIG_USB_C67X00_HCD is not set ++# CONFIG_USB_EHCI_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_OHCI_HCD is not set ++# CONFIG_USB_U132_HCD is not set ++# CONFIG_USB_SL811_HCD is not set ++# CONFIG_USB_R8A66597_HCD is not set ++CONFIG_USB_MUSB_HDRC=y ++# CONFIG_USB_MUSB_TUSB6010 is not set ++# CONFIG_USB_MUSB_OMAP2PLUS is not set ++# CONFIG_USB_MUSB_AM35X is not set ++CONFIG_USB_MUSB_DSPS=y ++CONFIG_MUSB_PIO_ONLY=y ++# CONFIG_USB_CHIPIDEA 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=m ++ ++# ++# 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 ++CONFIG_USB_UAS=y ++ ++# ++# USB Imaging devices ++# ++CONFIG_USB_MDC800=m ++CONFIG_USB_MICROTEK=m ++ ++# ++# USB port drivers ++# ++CONFIG_USB_SERIAL=m ++CONFIG_USB_SERIAL_GENERIC=y ++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_FUNSOFT=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_MOS7840=m ++CONFIG_USB_SERIAL_MOTOROLA=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_HP4X=m ++CONFIG_USB_SERIAL_SAFE=m ++# CONFIG_USB_SERIAL_SAFE_PADDED is not set ++CONFIG_USB_SERIAL_SIEMENS_MPI=m ++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_VIVOPAY_SERIAL=m ++CONFIG_USB_SERIAL_ZIO=m ++CONFIG_USB_SERIAL_ZTE=m ++CONFIG_USB_SERIAL_SSU100=m ++CONFIG_USB_SERIAL_QT2=m ++CONFIG_USB_SERIAL_DEBUG=m ++ ++# ++# USB Miscellaneous drivers ++# ++CONFIG_USB_EMI62=m ++CONFIG_USB_EMI26=m ++CONFIG_USB_ADUTUX=m ++CONFIG_USB_SEVSEG=m ++CONFIG_USB_RIO500=m ++CONFIG_USB_LEGOTOWER=m ++CONFIG_USB_LCD=m ++CONFIG_USB_LED=m ++CONFIG_USB_CYPRESS_CY7C63=m ++CONFIG_USB_CYTHERM=m ++CONFIG_USB_IDMOUSE=m ++CONFIG_USB_FTDI_ELAN=m ++CONFIG_USB_APPLEDISPLAY=m ++CONFIG_USB_SISUSBVGA=m ++CONFIG_USB_SISUSBVGA_CON=y ++CONFIG_USB_LD=m ++CONFIG_USB_TRANCEVIBRATOR=m ++CONFIG_USB_IOWARRIOR=m ++CONFIG_USB_TEST=m ++CONFIG_USB_ISIGHTFW=m ++CONFIG_USB_YUREX=m ++CONFIG_USB_EZUSB_FX2=m ++ ++# ++# USB Physical Layer drivers ++# ++CONFIG_OMAP_USB2=y ++CONFIG_USB_ISP1301=m ++CONFIG_USB_GADGET=y ++CONFIG_USB_GADGET_DEBUG=y ++CONFIG_USB_GADGET_DEBUG_FILES=y ++CONFIG_USB_GADGET_DEBUG_FS=y ++CONFIG_USB_GADGET_VBUS_DRAW=2 ++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 ++ ++# ++# USB Peripheral Controller ++# ++# CONFIG_USB_FUSB300 is not set ++# CONFIG_USB_R8A66597 is not set ++# CONFIG_USB_MV_UDC is not set ++CONFIG_USB_GADGET_MUSB_HDRC=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_ZERO is not set ++# CONFIG_USB_AUDIO is not set ++CONFIG_USB_ETH=m ++CONFIG_USB_ETH_RNDIS=y ++# CONFIG_USB_ETH_EEM is not set ++# CONFIG_USB_G_NCM is not set ++CONFIG_USB_GADGETFS=m ++# CONFIG_USB_FUNCTIONFS is not set ++# CONFIG_USB_FILE_STORAGE is not set ++CONFIG_USB_MASS_STORAGE=m ++CONFIG_USB_G_SERIAL=m ++# CONFIG_USB_MIDI_GADGET is not set ++# CONFIG_USB_G_PRINTER is not set ++CONFIG_USB_CDC_COMPOSITE=m ++# CONFIG_USB_G_NOKIA is not set ++# CONFIG_USB_G_ACM_MS is not set ++# CONFIG_USB_G_MULTI is not set ++CONFIG_USB_G_HID=m ++# CONFIG_USB_G_DBGP is not set ++# CONFIG_USB_G_WEBCAM is not set ++ ++# ++# OTG and related infrastructure ++# ++CONFIG_USB_OTG_UTILS=y ++CONFIG_USB_GPIO_VBUS=m ++# CONFIG_USB_ULPI is not set ++CONFIG_TWL4030_USB=y ++CONFIG_TWL6030_USB=y ++CONFIG_NOP_USB_XCEIV=y ++CONFIG_MMC=y ++# CONFIG_MMC_DEBUG is not set ++CONFIG_MMC_UNSAFE_RESUME=y ++# CONFIG_MMC_CLKGATE is not set ++ ++# ++# MMC/SD/SDIO Card Drivers ++# ++CONFIG_MMC_BLOCK=y ++CONFIG_MMC_BLOCK_MINORS=8 ++CONFIG_MMC_BLOCK_BOUNCE=y ++CONFIG_SDIO_UART=y ++# 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_OMAP=y ++CONFIG_MMC_OMAP_HS=y ++# CONFIG_MMC_DW is not set ++# CONFIG_MMC_VUB300 is not set ++# CONFIG_MMC_USHC is not set ++# CONFIG_MEMSTICK is not set ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y ++ ++# ++# LED drivers ++# ++# CONFIG_LEDS_LM3530 is not set ++CONFIG_LEDS_LM3642=m ++# 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_PCA955X is not set ++# CONFIG_LEDS_PCA9633 is not set ++# CONFIG_LEDS_DAC124S085 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=m ++# CONFIG_LEDS_OT200 is not set ++CONFIG_LEDS_BLINKM=m ++CONFIG_LEDS_TRIGGERS=y ++ ++# ++# LED Triggers ++# ++CONFIG_LEDS_TRIGGER_TIMER=y ++CONFIG_LEDS_TRIGGER_ONESHOT=y ++CONFIG_LEDS_TRIGGER_HEARTBEAT=y ++CONFIG_LEDS_TRIGGER_BACKLIGHT=y ++CONFIG_LEDS_TRIGGER_CPU=y ++CONFIG_LEDS_TRIGGER_GPIO=y ++CONFIG_LEDS_TRIGGER_DEFAULT_ON=y ++ ++# ++# iptables trigger is under Netfilter config (LED target) ++# ++CONFIG_LEDS_TRIGGER_TRANSIENT=y ++# CONFIG_ACCESSIBILITY is not set ++# CONFIG_EDAC is not set ++CONFIG_RTC_LIB=y ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_HCTOSYS=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_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_TWL4030=y ++# 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 ++ ++# ++# 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=m ++ ++# ++# on-CPU RTC drivers ++# ++CONFIG_RTC_DRV_SNVS=m ++CONFIG_DMADEVICES=y ++# CONFIG_DMADEVICES_DEBUG is not set ++ ++# ++# DMA Devices ++# ++# CONFIG_DW_DMAC is not set ++# CONFIG_TIMB_DMA is not set ++CONFIG_TI_EDMA=y ++# CONFIG_DMA_OMAP is not set ++CONFIG_DMA_ENGINE=y ++CONFIG_DMA_VIRTUAL_CHANNELS=y ++ ++# ++# DMA Clients ++# ++CONFIG_NET_DMA=y ++CONFIG_ASYNC_TX_DMA=y ++CONFIG_DMATEST=m ++# CONFIG_AUXDISPLAY is not set ++CONFIG_UIO=y ++CONFIG_UIO_PDRV=y ++CONFIG_UIO_PDRV_GENIRQ=y ++CONFIG_VIRTIO=m ++ ++# ++# Virtio drivers ++# ++# CONFIG_VIRTIO_BALLOON is not set ++# CONFIG_VIRTIO_MMIO is not set ++ ++# ++# Microsoft Hyper-V guest support ++# ++# CONFIG_STAGING is not set ++CONFIG_CLKDEV_LOOKUP=y ++CONFIG_HWSPINLOCK=m ++ ++# ++# Hardware Spinlock drivers ++# ++CONFIG_HWSPINLOCK_OMAP=m ++CONFIG_CLKSRC_MMIO=y ++CONFIG_IOMMU_SUPPORT=y ++CONFIG_OF_IOMMU=y ++# CONFIG_OMAP_IOMMU is not set ++ ++# ++# Remoteproc drivers (EXPERIMENTAL) ++# ++CONFIG_REMOTEPROC=m ++CONFIG_STE_MODEM_RPROC=m ++ ++# ++# Rpmsg drivers (EXPERIMENTAL) ++# ++# CONFIG_VIRT_DRIVERS is not set ++# CONFIG_PM_DEVFREQ is not set ++# CONFIG_EXTCON is not set ++# CONFIG_MEMORY is not set ++CONFIG_IIO=y ++CONFIG_IIO_BUFFER=y ++CONFIG_IIO_KFIFO_BUF=m ++CONFIG_IIO_TRIGGERED_BUFFER=m ++CONFIG_IIO_TRIGGER=y ++CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 ++ ++# ++# Accelerometers ++# ++CONFIG_HID_SENSOR_ACCEL_3D=m ++ ++# ++# Analog to digital converters ++# ++CONFIG_AD_SIGMA_DELTA=m ++CONFIG_AD7266=m ++CONFIG_AD7791=m ++CONFIG_AD7476=m ++CONFIG_TI_AM335X_ADC=y ++ ++# ++# Amplifiers ++# ++# CONFIG_AD8366 is not set ++ ++# ++# Light sensors ++# ++CONFIG_ADJD_S311=m ++CONFIG_VCNL4000=m ++CONFIG_HID_SENSOR_ALS=m ++ ++# ++# Frequency Synthesizers DDS/PLL ++# ++ ++# ++# Clock Generator/Distribution ++# ++CONFIG_AD9523=m ++ ++# ++# Phase-Locked Loop (PLL) frequency synthesizers ++# ++CONFIG_ADF4350=m ++ ++# ++# Digital to analog converters ++# ++CONFIG_AD5064=m ++CONFIG_AD5360=m ++CONFIG_AD5380=m ++CONFIG_AD5421=m ++CONFIG_AD5624R_SPI=m ++CONFIG_AD5446=m ++CONFIG_AD5504=m ++CONFIG_AD5755=m ++CONFIG_AD5764=m ++CONFIG_AD5791=m ++CONFIG_AD5686=m ++CONFIG_MAX517=m ++CONFIG_MCP4725=m ++ ++# ++# Hid Sensor IIO Common ++# ++CONFIG_HID_SENSOR_IIO_COMMON=m ++CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS=m ++ ++# ++# Digital gyroscope sensors ++# ++CONFIG_HID_SENSOR_GYRO_3D=m ++ ++# ++# Light sensors ++# ++ ++# ++# Magnetometer sensors ++# ++CONFIG_HID_SENSOR_MAGNETOMETER_3D=m ++CONFIG_PWM=y ++CONFIG_PWM_TIECAP=y ++CONFIG_PWM_TIEHRPWM=y ++# CONFIG_PWM_TWL6030 is not set ++CONFIG_EHRPWM_TEST=m ++ ++# ++# CAPEBUS support ++# ++CONFIG_CAPEBUS=y ++CONFIG_CAPEBUS_BONE_CONTROLLER=y ++CONFIG_CAPEBUS_BONE_GENERIC=y ++CONFIG_CAPEBUS_BONE_GEIGER=y ++ ++# ++# File systems ++# ++CONFIG_DCACHE_WORD_ACCESS=y ++CONFIG_EXT2_FS=y ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XIP is not set ++CONFIG_EXT3_FS=y ++CONFIG_EXT3_DEFAULTS_TO_ORDERED=y ++# CONFIG_EXT3_FS_XATTR is not set ++CONFIG_EXT4_FS=y ++CONFIG_EXT4_FS_XATTR=y ++# CONFIG_EXT4_FS_POSIX_ACL is not set ++# CONFIG_EXT4_FS_SECURITY is not set ++# CONFIG_EXT4_DEBUG is not set ++CONFIG_JBD=y ++# CONFIG_JBD_DEBUG is not set ++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 is not set ++# CONFIG_REISERFS_FS_XATTR is not set ++CONFIG_JFS_FS=m ++# CONFIG_JFS_POSIX_ACL is not set ++# CONFIG_JFS_SECURITY is not set ++# CONFIG_JFS_DEBUG is not set ++# CONFIG_JFS_STATISTICS is not set ++CONFIG_XFS_FS=m ++CONFIG_XFS_QUOTA=y ++CONFIG_XFS_POSIX_ACL=y ++CONFIG_XFS_RT=y ++# CONFIG_XFS_DEBUG is not set ++CONFIG_GFS2_FS=m ++CONFIG_BTRFS_FS=m ++# CONFIG_BTRFS_FS_POSIX_ACL is not set ++# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set ++CONFIG_NILFS2_FS=m ++CONFIG_FS_POSIX_ACL=y ++CONFIG_EXPORTFS=m ++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=m ++ ++# ++# Caches ++# ++# CONFIG_FSCACHE is not set ++ ++# ++# CD-ROM/DVD Filesystems ++# ++# CONFIG_ISO9660_FS is not set ++# CONFIG_UDF_FS is not set ++ ++# ++# 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 is not set ++ ++# ++# 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 is not set ++# CONFIG_TMPFS_XATTR is not set ++# CONFIG_HUGETLB_PAGE is not set ++# CONFIG_CONFIGFS_FS is not set ++CONFIG_MISC_FILESYSTEMS=y ++# CONFIG_ADFS_FS is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_ECRYPT_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_HFSPLUS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++CONFIG_JFFS2_FS_WRITEBUFFER=y ++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set ++CONFIG_JFFS2_SUMMARY=y ++CONFIG_JFFS2_FS_XATTR=y ++CONFIG_JFFS2_FS_POSIX_ACL=y ++CONFIG_JFFS2_FS_SECURITY=y ++CONFIG_JFFS2_COMPRESSION_OPTIONS=y ++CONFIG_JFFS2_ZLIB=y ++CONFIG_JFFS2_LZO=y ++CONFIG_JFFS2_RTIME=y ++CONFIG_JFFS2_RUBIN=y ++# CONFIG_JFFS2_CMODE_NONE is not set ++CONFIG_JFFS2_CMODE_PRIORITY=y ++# CONFIG_JFFS2_CMODE_SIZE is not set ++# CONFIG_JFFS2_CMODE_FAVOURLZO is not set ++CONFIG_UBIFS_FS=y ++# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set ++CONFIG_UBIFS_FS_LZO=y ++CONFIG_UBIFS_FS_ZLIB=y ++# CONFIG_LOGFS is not set ++CONFIG_CRAMFS=y ++# CONFIG_SQUASHFS is not set ++# 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=y ++CONFIG_F2FS_STAT_FS=y ++CONFIG_F2FS_FS_XATTR=y ++CONFIG_F2FS_FS_POSIX_ACL=y ++CONFIG_NETWORK_FILESYSTEMS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V2=y ++CONFIG_NFS_V3=y ++CONFIG_NFS_V3_ACL=y ++CONFIG_NFS_V4=y ++CONFIG_NFS_SWAP=y ++# CONFIG_NFS_V4_1 is not set ++CONFIG_ROOT_NFS=y ++# CONFIG_NFS_USE_LEGACY_DNS is not set ++CONFIG_NFS_USE_KERNEL_DNS=y ++# CONFIG_NFSD is not set ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++CONFIG_NFS_ACL_SUPPORT=y ++CONFIG_NFS_COMMON=y ++CONFIG_SUNRPC=y ++CONFIG_SUNRPC_GSS=y ++CONFIG_SUNRPC_SWAP=y ++# CONFIG_SUNRPC_DEBUG is not set ++# CONFIG_CEPH_FS is not set ++# CONFIG_CIFS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_CODA_FS is not set ++# CONFIG_AFS_FS is not set ++# CONFIG_9P_FS is not set ++CONFIG_NLS=y ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=y ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++# CONFIG_NLS_ASCII is not set ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_MAC_ROMAN is not set ++# CONFIG_NLS_MAC_CELTIC is not set ++# CONFIG_NLS_MAC_CENTEURO is not set ++# CONFIG_NLS_MAC_CROATIAN is not set ++# CONFIG_NLS_MAC_CYRILLIC is not set ++# CONFIG_NLS_MAC_GAELIC is not set ++# CONFIG_NLS_MAC_GREEK is not set ++# CONFIG_NLS_MAC_ICELAND is not set ++# CONFIG_NLS_MAC_INUIT is not set ++# CONFIG_NLS_MAC_ROMANIAN is not set ++# CONFIG_NLS_MAC_TURKISH is not set ++# CONFIG_NLS_UTF8 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 is not set ++# CONFIG_UNUSED_SYMBOLS is not set ++CONFIG_DEBUG_FS=y ++# CONFIG_HEADERS_CHECK is not set ++# CONFIG_DEBUG_SECTION_MISMATCH is not set ++CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_SHIRQ is not set ++# CONFIG_LOCKUP_DETECTOR is not set ++# CONFIG_PANIC_ON_OOPS is not set ++CONFIG_PANIC_ON_OOPS_VALUE=0 ++# CONFIG_DETECT_HUNG_TASK is not set ++CONFIG_SCHED_DEBUG=y ++CONFIG_SCHEDSTATS=y ++CONFIG_TIMER_STATS=y ++# CONFIG_DEBUG_OBJECTS is not set ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_HAVE_DEBUG_KMEMLEAK=y ++# CONFIG_DEBUG_KMEMLEAK is not set ++# 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_SPARSE_RCU_POINTER 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=y ++CONFIG_DEBUG_INFO_REDUCED=y ++# 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 ++# CONFIG_RCU_TORTURE_TEST is not set ++CONFIG_RCU_CPU_STALL_TIMEOUT=60 ++# CONFIG_RCU_CPU_STALL_INFO is not set ++# CONFIG_RCU_TRACE is not set ++# CONFIG_KPROBES_SANITY_TEST 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=m ++# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set ++CONFIG_PM_NOTIFIER_ERROR_INJECT=m ++# CONFIG_FAULT_INJECTION is not set ++# CONFIG_DEBUG_PAGEALLOC is not set ++CONFIG_NOP_TRACER=y ++CONFIG_HAVE_FUNCTION_TRACER=y ++CONFIG_HAVE_DYNAMIC_FTRACE=y ++CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y ++CONFIG_HAVE_SYSCALL_TRACEPOINTS=y ++CONFIG_HAVE_C_RECORDMCOUNT=y ++CONFIG_TRACE_CLOCK=y ++CONFIG_RING_BUFFER=y ++CONFIG_EVENT_TRACING=y ++CONFIG_EVENT_POWER_TRACING_DEPRECATED=y ++CONFIG_CONTEXT_SWITCH_TRACER=y ++CONFIG_RING_BUFFER_ALLOW_SWAP=y ++CONFIG_TRACING=y ++CONFIG_TRACING_SUPPORT=y ++CONFIG_FTRACE=y ++# CONFIG_FUNCTION_TRACER is not set ++# CONFIG_IRQSOFF_TRACER is not set ++# CONFIG_SCHED_TRACER is not set ++# CONFIG_ENABLE_DEFAULT_TRACERS is not set ++# CONFIG_FTRACE_SYSCALLS 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_KPROBE_EVENT=y ++CONFIG_PROBE_EVENTS=y ++# CONFIG_RING_BUFFER_BENCHMARK 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_SAMPLES is not set ++CONFIG_HAVE_ARCH_KGDB=y ++# CONFIG_KGDB 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_LL is not set ++CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" ++# CONFIG_ARM_KPROBES_TEST is not set ++# 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 is not set ++# CONFIG_SECURITY_PATH is not set ++# CONFIG_SECURITY_TOMOYO is not set ++# CONFIG_SECURITY_APPARMOR is not set ++# CONFIG_SECURITY_YAMA is not set ++# CONFIG_IMA is not set ++# CONFIG_EVM is not set ++CONFIG_DEFAULT_SECURITY_DAC=y ++CONFIG_DEFAULT_SECURITY="" ++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=m ++CONFIG_CRYPTO_BLKCIPHER2=y ++CONFIG_CRYPTO_HASH=y ++CONFIG_CRYPTO_HASH2=y ++CONFIG_CRYPTO_RNG2=y ++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 is not set ++# CONFIG_CRYPTO_NULL is not set ++CONFIG_CRYPTO_PCRYPT=y ++CONFIG_CRYPTO_WORKQUEUE=y ++# CONFIG_CRYPTO_CRYPTD is not set ++CONFIG_CRYPTO_AUTHENC=m ++# CONFIG_CRYPTO_TEST is not set ++ ++# ++# Authenticated Encryption with Associated Data ++# ++# CONFIG_CRYPTO_CCM is not set ++# CONFIG_CRYPTO_GCM is not set ++# CONFIG_CRYPTO_SEQIV is not set ++ ++# ++# Block modes ++# ++CONFIG_CRYPTO_CBC=m ++# CONFIG_CRYPTO_CTR is not set ++# CONFIG_CRYPTO_CTS is not set ++CONFIG_CRYPTO_ECB=m ++# CONFIG_CRYPTO_LRW is not set ++# CONFIG_CRYPTO_PCBC is not set ++# CONFIG_CRYPTO_XTS is not set ++ ++# ++# Hash modes ++# ++CONFIG_CRYPTO_HMAC=m ++# CONFIG_CRYPTO_XCBC is not set ++# CONFIG_CRYPTO_VMAC is not set ++ ++# ++# Digest ++# ++CONFIG_CRYPTO_CRC32C=y ++# CONFIG_CRYPTO_GHASH is not set ++# CONFIG_CRYPTO_MD4 is not set ++CONFIG_CRYPTO_MD5=m ++CONFIG_CRYPTO_MICHAEL_MIC=y ++# CONFIG_CRYPTO_RMD128 is not set ++# CONFIG_CRYPTO_RMD160 is not set ++# CONFIG_CRYPTO_RMD256 is not set ++# CONFIG_CRYPTO_RMD320 is not set ++CONFIG_CRYPTO_SHA1=m ++# CONFIG_CRYPTO_SHA1_ARM is not set ++# CONFIG_CRYPTO_SHA256 is not set ++# CONFIG_CRYPTO_SHA512 is not set ++# CONFIG_CRYPTO_TGR192 is not set ++# CONFIG_CRYPTO_WP512 is not set ++ ++# ++# Ciphers ++# ++CONFIG_CRYPTO_AES=y ++CONFIG_CRYPTO_AES_ARM=y ++# CONFIG_CRYPTO_ANUBIS is not set ++CONFIG_CRYPTO_ARC4=m ++# CONFIG_CRYPTO_BLOWFISH is not set ++# CONFIG_CRYPTO_CAMELLIA is not set ++# CONFIG_CRYPTO_CAST5 is not set ++# CONFIG_CRYPTO_CAST6 is not set ++CONFIG_CRYPTO_DES=m ++# CONFIG_CRYPTO_FCRYPT is not set ++# CONFIG_CRYPTO_KHAZAD is not set ++# CONFIG_CRYPTO_SALSA20 is not set ++# CONFIG_CRYPTO_SEED is not set ++# CONFIG_CRYPTO_SERPENT is not set ++# CONFIG_CRYPTO_TEA is not set ++# CONFIG_CRYPTO_TWOFISH is not set ++ ++# ++# Compression ++# ++CONFIG_CRYPTO_DEFLATE=y ++# CONFIG_CRYPTO_ZLIB is not set ++CONFIG_CRYPTO_LZO=y ++ ++# ++# Random Number Generation ++# ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++# CONFIG_CRYPTO_USER_API_HASH is not set ++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set ++CONFIG_CRYPTO_HW=y ++# CONFIG_CRYPTO_DEV_OMAP_SHAM is not set ++# CONFIG_CRYPTO_DEV_OMAP_AES is not set ++CONFIG_ASYMMETRIC_KEY_TYPE=m ++CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m ++CONFIG_PUBLIC_KEY_ALGO_RSA=m ++CONFIG_X509_CERTIFICATE_PARSER=m ++CONFIG_BINARY_PRINTF=y ++ ++# ++# Library routines ++# ++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_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=y ++CONFIG_LZO_COMPRESS=y ++CONFIG_LZO_DECOMPRESS=y ++# CONFIG_XZ_DEC is not set ++# CONFIG_XZ_DEC_BCJ is not set ++CONFIG_DECOMPRESS_GZIP=y ++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_AVERAGE=y ++CONFIG_CLZ_TAB=y ++# CONFIG_CORDIC is not set ++# CONFIG_DDR is not set ++CONFIG_MPILIB=m ++CONFIG_OID_REGISTRY=m diff --git a/patches/linux-3.7-rc6/0139-capebus-Geiger-Cape-config-bugfixs.patch b/patches/linux-3.7-rc6/0139-capebus-Geiger-Cape-config-bugfixs.patch new file mode 100644 index 0000000..3af0453 --- /dev/null +++ b/patches/linux-3.7-rc6/0139-capebus-Geiger-Cape-config-bugfixs.patch @@ -0,0 +1,27 @@ +From 441e11b11ca8dcca74fb85715a204a52899feb49 Mon Sep 17 00:00:00 2001 +From: Matt Ranostay <mranostay@gmail.com> +Date: Sun, 18 Nov 2012 23:26:20 +0000 +Subject: [PATCH] capebus: Geiger Cape config bugfixs + +The display of 'vsense-name' default is incorrect. + +Signed-off-by: Matt Ranostay <mranostay@gmail.com> +--- + drivers/capebus/capes/bone-geiger-cape.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/capebus/capes/bone-geiger-cape.c b/drivers/capebus/capes/bone-geiger-cape.c +index 880eaae..9e53d8d 100644 +--- a/drivers/capebus/capes/bone-geiger-cape.c ++++ b/drivers/capebus/capes/bone-geiger-cape.c +@@ -417,8 +417,8 @@ static int bonegeiger_probe(struct cape_dev *dev, const struct cape_device_id *i + "vsense-name", &info->vsense_name) != 0) { + info->vsense_name = "AIN5"; + dev_warn(&dev->dev, "Could not read vsense-name property; " +- "using default %u\n", +- val); ++ "using default '%s'\n", ++ info->vsense_name); + } + + if (capebus_of_property_read_u32(dev, diff --git a/patches/linux-3.7-rc6/series b/patches/linux-3.7-rc6/series new file mode 100644 index 0000000..2c0930a --- /dev/null +++ b/patches/linux-3.7-rc6/series @@ -0,0 +1,128 @@ +0000-linux-master.patch +0001-video-st7735fb-add-st7735-framebuffer-driver.patch +0002-regulator-tps65910-fix-BUG_ON-shown-with-vrtc-regula.patch +0003-dmaengine-add-helper-function-to-request-a-slave-DMA.patch +0004-of-Add-generic-device-tree-DMA-helpers.patch +0005-of-dma-fix-build-break-for-CONFIG_OF.patch +0006-of-dma-fix-typos-in-generic-dma-binding-definition.patch +0007-dmaengine-fix-build-failure-due-to-missing-semi-colo.patch +0008-dmaengine-edma-fix-slave-config-dependency-on-direct.patch +0009-ARM-davinci-move-private-EDMA-API-to-arm-common.patch +0010-ARM-edma-remove-unused-transfer-controller-handlers.patch +0011-ARM-edma-add-DT-and-runtime-PM-support-for-AM33XX.patch +0012-ARM-edma-add-AM33XX-crossbar-event-support.patch +0013-dmaengine-edma-enable-build-for-AM33XX.patch +0014-dmaengine-edma-Add-TI-EDMA-device-tree-binding.patch +0015-ARM-dts-add-AM33XX-EDMA-support.patch +0016-dmaengine-add-dma_request_slave_channel_compat.patch +0017-mmc-omap_hsmmc-convert-to-dma_request_slave_channel_.patch +0018-mmc-omap_hsmmc-limit-max_segs-with-the-EDMA-DMAC.patch +0019-mmc-omap_hsmmc-add-generic-DMA-request-support-to-th.patch +0020-ARM-dts-add-AM33XX-MMC-support.patch +0021-spi-omap2-mcspi-convert-to-dma_request_slave_channel.patch +0022-spi-omap2-mcspi-add-generic-DMA-request-support-to-t.patch +0023-ARM-dts-add-AM33XX-SPI-support.patch +0024-Documentation-bindings-add-spansion.patch +0025-ARM-dts-add-BeagleBone-Adafruit-1.8-LCD-support.patch +0026-misc-add-gpevt-driver.patch +0027-ARM-dts-add-BeagleBone-gpevt-support.patch +0028-ARM-configs-working-AM33XX-edma-dmaengine-defconfig.patch +0029-ARM-configs-working-da850-edma-dmaengine-defconfig.patch +0030-misc-gpevt-null-terminate-the-of_match_table.patch +0031-proposed-probe-fix-works-for-me-on-evm.patch +0033-ARM-OMAP3-hwmod-Add-AM33XX-HWMOD-data-for-davinci_md.patch +0034-net-davinci_mdio-Fix-type-mistake-in-calling-runtime.patch +0035-net-cpsw-Add-parent-child-relation-support-between-c.patch +0036-arm-dts-am33xx-Add-cpsw-and-mdio-module-nodes-for-AM.patch +0038-i2c-pinctrl-ify-i2c-omap.c.patch +0039-arm-dts-AM33XX-Configure-pinmuxs-for-user-leds-contr.patch +0040-beaglebone-DT-set-default-triggers-for-LEDS.patch +0041-beaglebone-add-a-cpu-led-trigger.patch +0043-arm-dts-AM33XX-Add-device-tree-OPP-table.patch +0045-input-TSC-ti_tscadc-Correct-register-usage.patch +0046-input-TSC-ti_tscadc-Add-Step-configuration-as-platfo.patch +0047-input-TSC-ti_tscadc-set-FIFO0-threshold-Interrupt.patch +0048-input-TSC-ti_tscadc-Remove-definition-of-End-Of-Inte.patch +0049-input-TSC-ti_tscadc-Rename-the-existing-touchscreen-.patch +0050-MFD-ti_tscadc-Add-support-for-TI-s-TSC-ADC-MFDevice.patch +0051-input-TSC-ti_tsc-Convert-TSC-into-a-MFDevice.patch +0052-IIO-ADC-tiadc-Add-support-of-TI-s-ADC-driver.patch +0053-input-ti_am335x_tsc-Make-steps-enable-configurable.patch +0054-input-ti_am335x_tsc-Order-of-TSC-wires-connect-made-.patch +0055-input-ti_am335x_tsc-Add-variance-filters.patch +0056-ti_tscadc-Update-with-IIO-map-interface-deal-with-pa.patch +0057-ti_tscadc-Match-mfd-sub-devices-to-regmap-interface.patch +0059-ARM-OMAP3-hwmod-Corrects-resource-data-for-PWM-devic.patch +0060-pwm_backlight-Add-device-tree-support-for-Low-Thresh.patch +0061-pwm-pwm-tiecap-Add-device-tree-binding-support-in-AP.patch +0062-Control-module-EHRPWM-clk-enabling.patch +0063-pwm-pwm-tiecap-Enable-clock-gating.patch +0064-PWM-ti-ehrpwm-fix-up-merge-conflict.patch +0065-pwm-pwm_test-Driver-support-for-PWM-module-testing.patch +0066-arm-dts-DT-support-for-EHRPWM-and-ECAP-device.patch +0067-pwm-pwm-tiehrpwm-Add-device-tree-binding-support-EHR.patch +0069-pinctrl-pinctrl-single-must-be-initialized-early.patch +0070-Bone-DTS-working-i2c2-i2c3-in-the-tree.patch +0071-am33xx-Convert-I2C-from-omap-to-am33xx-names.patch +0072-beaglebone-fix-backlight-entry-in-DT.patch +0074-Shut-up-musb.patch +0075-musb-Fix-crashes-and-other-weirdness.patch +0076-musb-revert-parts-of-032ec49f.patch +0077-usb-musb-dsps-get-the-PHY-using-phandle-api.patch +0078-drivers-usb-otg-add-device-tree-support-to-otg-libra.patch +0079-usb-otg-nop-add-dt-support.patch +0080-usb-musb-dsps-add-phy-control-logic-to-glue.patch +0081-usb-musb-dsps-enable-phy-control-for-am335x.patch +0082-ARM-am33xx-fix-mem-regions-in-USB-hwmod.patch +0084-omap2-clk-Add-missing-lcdc-clock-definition.patch +0085-da8xx-Allow-use-by-am33xx-based-devices.patch +0086-da8xx-Fix-revision-check-on-the-da8xx-driver.patch +0087-da8xx-De-constify-members-in-the-platform-config.patch +0088-da8xx-Add-standard-panel-definition.patch +0089-da8xx-Add-CDTech_S035Q01-panel-used-by-LCD3-bone-cap.patch +0090-da8xx-fb-add-panel-definition-for-beaglebone-LCD7-ca.patch +0092-mmc-omap_hsmmc-Enable-HSPE-bit-for-high-speed-cards.patch +0093-am33xx.dtsi-enable-MMC-HSPE-bit-for-all-3-controller.patch +0094-omap-hsmmc-Correct-usage-of-of_find_node_by_name.patch +0096-ARM-AM33XX-hwmod-Remove-wrong-INIT_NO_RESET-IDLE-fla.patch +0098-f2fs-add-document.patch +0099-f2fs-add-on-disk-layout.patch +0100-f2fs-add-superblock-and-major-in-memory-structure.patch +0101-f2fs-add-super-block-operations.patch +0102-f2fs-add-checkpoint-operations.patch +0103-f2fs-add-node-operations.patch +0104-f2fs-add-segment-operations.patch +0105-f2fs-add-file-operations.patch +0106-f2fs-add-address-space-operations-for-data.patch +0107-f2fs-add-core-inode-operations.patch +0108-f2fs-add-inode-operations-for-special-inodes.patch +0109-f2fs-add-core-directory-operations.patch +0110-f2fs-add-xattr-and-acl-functionalities.patch +0111-f2fs-add-garbage-collection-functions.patch +0112-f2fs-add-recovery-routines-for-roll-forward.patch +0113-f2fs-update-Kconfig-and-Makefile.patch +0114-f2fs-gc.h-make-should_do_checkpoint-inline.patch +0115-f2fs-move-statistics-code-into-one-file.patch +0116-f2fs-move-proc-files-to-debugfs.patch +0117-f2fs-compile-fix.patch +0119-i2c-EEPROM-Export-memory-accessor.patch +0120-omap-Export-omap_hwmod_lookup-omap_device_build-omap.patch +0121-gpio-keys-Pinctrl-fy.patch +0122-tps65217-Allow-placement-elsewhere-than-parent-mfd-d.patch +0123-pwm-export-of_pwm_request.patch +0124-i2c-Export-capability-to-probe-devices.patch +0125-pwm-backlight-Pinctrl-fy.patch +0126-spi-Export-OF-interfaces-for-capebus-use.patch +0127-w1-gpio-Pinctrl-fy.patch +0128-w1-gpio-Simplify-get-rid-of-defines.patch +0129-arm-dt-Enable-DT-proc-updates.patch +0130-ARM-CUSTOM-Build-a-uImage-with-dtb-already-appended.patch +0131-beaglebone-create-a-shared-dtsi-for-beaglebone-based.patch +0132-beaglebone-enable-emmc-for-bonelt.patch +0133-capebus-Core-capebus-support.patch +0134-capebus-Add-beaglebone-board-support.patch +0135-capebus-Beaglebone-generic-board.patch +0136-capebus-Add-beaglebone-geiger-cape.patch +0137-capebus-Beaglebone-capebus-DT-update.patch +0138-beaglebone-Update-default-config-for-capebus.patch +0139-capebus-Geiger-Cape-config-bugfixs.patch diff --git a/platformconfig b/platformconfig index c706a9d..726a692 100644 --- a/platformconfig +++ b/platformconfig @@ -1,8 +1,8 @@ # # Automatically generated make config: don't edit -# PTXdist 2012.09.1 +# PTXdist 2012.10.0-00092-g335bb61 # -PTXCONF_PLATFORMCONFIG_VERSION="2012.09.1" +PTXCONF_PLATFORMCONFIG_VERSION="2012.10.0-00092-g335bb61" PTXCONF_RUNTIME=y PTXCONF_BUILDTIME=y PTXCONF__platformconfig_MAGIC__=y @@ -19,7 +19,7 @@ PTXCONF__platformconfig_MAGIC__=y # ------------------------------------ # PTXCONF_PLATFORM="pengutronix-beagleboneti" -PTXCONF_PLATFORM_VERSION="-2012.09.1" +PTXCONF_PLATFORM_VERSION="-2012.10.0+master" # # architecture @@ -83,8 +83,8 @@ PTXCONF_KERNEL_INSTALL=y PTXCONF_KERNEL_MODULES=y PTXCONF_KERNEL_MODULES_INSTALL=y PTXCONF_KERNEL_MODULES_BUILD="modules" -PTXCONF_KERNEL_VERSION="3.2.16" -PTXCONF_KERNEL_MD5="8719646144bbadf51ab79e797a0ee0ee" +PTXCONF_KERNEL_VERSION="3.7-rc6" +PTXCONF_KERNEL_MD5="66a670a84bacec902d548362e9679112" PTXCONF_KERNEL_ARCH_STRING="arm" # PTXCONF_KERNEL_IMAGE_BZ is not set # PTXCONF_KERNEL_IMAGE_Z is not set @@ -95,6 +95,7 @@ PTXCONF_KERNEL_IMAGE_U=y # PTXCONF_KERNEL_IMAGE_RAW is not set # PTXCONF_KERNEL_IMAGE_SIMPLE is not set PTXCONF_KERNEL_IMAGE="uImage" +PTXCONF_KERNEL_DTC=y PTXCONF_KERNEL_XZ=y PTXCONF_KERNEL_LZOP=y @@ -102,14 +103,17 @@ PTXCONF_KERNEL_LZOP=y # patching & configuration # PTXCONF_KERNEL_SERIES="series" -PTXCONF_KERNEL_CONFIG="kernelconfig-${PTXCONF_KERNEL_VERSION}" +PTXCONF_KERNEL_CONFIG="kernelconfig" # # Development features # PTXCONF_KERNEL_EXTRA_MAKEVARS="CONFIG_DEBUG_SECTION_MISMATCH=y" -# PTXCONF_HOST_DTC is not set -# PTXCONF_DTC is not set +PTXCONF_DTC=y +# PTXCONF_DTC_INSTALL_OFTREE is not set +PTXCONF_DTC_OFTREE_DTS="${KERNEL_DIR}/arch/arm/boot/dts/am335x-bone.dts" +PTXCONF_DTC_KERNEL=y +PTXCONF_DTC_EXTRA_ARGS="" # # console options @@ -186,6 +190,8 @@ PTXCONF_IMAGE_VFAT_TOOLS=y # new image creation options # PTXCONF_IMAGE_BOOT_MLO=y +# PTXCONF_IMAGE_ROOT_CPIO_GZ is not set +# PTXCONF_IMAGE_ROOT_CPIO is not set PTXCONF_IMAGE_ROOT_EXT=y PTXCONF_IMAGE_ROOT_EXT_SIZE="256M" # PTXCONF_IMAGE_ROOT_EXT_EXT2 is not set @@ -194,7 +200,6 @@ PTXCONF_IMAGE_ROOT_EXT_EXT4=y PTXCONF_IMAGE_ROOT_EXT_TYPE="ext4" PTXCONF_IMAGE_ROOT_TGZ=y PTXCONF_IMAGE_SD=y -PTXCONF_CROSS_MODULE_INIT_TOOLS=y # PTXCONF_HOST_CDRKIT is not set # PTXCONF_HOST_CMAKE is not set # PTXCONF_HOST_CRAMFS is not set @@ -209,6 +214,7 @@ PTXCONF_HOST_GENIMAGE=y # PTXCONF_HOST_LIBBZ2 is not set # PTXCONF_HOST_LIBCAP is not set PTXCONF_HOST_LIBCONFUSE=y +PTXCONF_HOST_LIBKMOD=y PTXCONF_HOST_LIBLZO=y # PTXCONF_HOST_LIBUUID is not set PTXCONF_HOST_LZOP=y |